Фиксация мамы нолнан с сфере 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
+1
View File
@@ -0,0 +1 @@
.kiro/settings/lsp.json
+158
View File
@@ -0,0 +1,158 @@
# FoxLang 5.0.1 - Changelog
## 🆕 Новые возможности
### Встроенная функция read_file()
- **Чтение файлов:** Новая функция `read_file(filename)` для чтения текстовых файлов
- **Умная обработка:** Автоматически пропускает комментарии (строки начинающиеся с #) и пустые строки
- **Безопасность:** Возвращает пустую строку при ошибке чтения файла
- **Применение:** Идеально подходит для чтения конфигурационных файлов
### Встроенная функция http_get()
- **HTTP запросы:** Новая функция `http_get(url)` для выполнения GET запросов
- **Простота использования:** Один вызов функции для получения данных с сервера
- **Интеграция:** Использует системный curl для надежности
- **Применение:** Работа с API, загрузка данных, веб-скрапинг
```cpp
string config = read_file("config.txt");
if (config != "") {
print("Config loaded: " + config);
}
```
---
# FoxLang 5.0.0 - Changelog
## 🚀 Крупные нововведения
### 1. Пользовательские функции
- **Полная поддержка функций** с параметрами и возвратом значений
- **Локальные области видимости** для параметров функций
- **Рекурсивные вызовы** функций
- **Поддержка всех типов** в параметрах и возврате (`int`, `float`, `string`, `bool`, `void`)
```cpp
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
```
### 2. Модульная система с пользовательскими функциями
- **Библиотеки с функциями**: Теперь `include("lib.fox")` поддерживает пользовательские функции
- **Правильная область видимости**: Функции из библиотек доступны в основном коде
- **Режим импорта**: Функции регистрируются, но код библиотеки не выполняется
```cpp
// math_lib.fox
int add(int a, int b) {
return a + b;
}
// main.fox
include("math_lib.fox");
int result = add(5, 3); // Работает!
```
### 3. Современный синтаксис идентификаторов
- **Поддержка подчеркиваний**: `user_name`, `get_public_ip`, `my_function`
- **Исправлен лексер**: Идентификаторы с `_` не конфликтуют с ключевыми словами
- **Совместимость**: Все существующие имена переменных продолжают работать
### 4. Расширенная поддержка циклов
- **Цикл for**: Полная поддержка `for (init; condition; step) { ... }`
- **Улучшенные while циклы**: Лучшая обработка условий
- **Вложенные циклы**: Поддержка любого уровня вложенности
## 🔧 Технические улучшения
### Парсер и AST
- **Новые узлы**: `FuncDefNode`, `ReturnNode`, `ForNode`
- **Улучшенная обработка**: `return` внутри функций
- **Контекст функций**: Изолированные области видимости
- **Обработка ошибок**: Лучшие сообщения об ошибках
### Лексер
- **Исправлена логика**: Идентификаторы с подчеркиваниями обрабатываются корректно
- **Приоритет ключевых слов**: Только полные совпадения считаются ключевыми словами
## 📋 Примеры использования
### Пользовательские функции
```cpp
string greet(string name, int age) {
return "Hello, " + name + "! You are " + age + " years old.";
}
void main() {
string message = greet("Alice", 25);
print(message);
}
main();
```
### Библиотеки с функциями
```cpp
// utils.fox
int max(int a, int b) {
if (a > b) return a;
return b;
}
void print_array(array arr, int size) {
int i = 0;
while (i < size) {
print("arr[" + i + "] = " + get(arr, i));
i = i + 1;
}
}
// main.fox
include("utils.fox");
int maximum = max(10, 20);
array numbers 3;
set(numbers, 0, 5);
set(numbers, 1, 10);
set(numbers, 2, 15);
print_array(numbers, 3);
```
### Современный синтаксис
```cpp
string user_name = "john_doe";
int user_age = 25;
bool is_admin = false;
string get_user_info() {
return "User: " + user_name + ", Age: " + user_age;
}
void check_permissions() {
if (is_admin) {
print("Admin access granted");
} else {
print("Regular user access");
}
}
```
## 🔄 Обратная совместимость
- Все скрипты FoxLang 4.x продолжают работать
- Встроенные функции (`print`, `input`, `fox`) не изменились
- Синтаксис массивов и переменных остался прежним
## 🐛 Исправленные ошибки
- Исправлена обработка идентификаторов с подчеркиваниями
- Устранены конфликты ключевых слов с именами функций
- Улучшена стабильность парсера при обработке функций
- Исправлены ошибки области видимости переменных
---
**Версия 5.0.0** представляет собой значительный шаг вперед в развитии FoxLang, превращая его в полноценный язык программирования с поддержкой пользовательских функций и современной модульной системы.
+115 -31
View File
@@ -1,14 +1,15 @@
# 📚 Документация FoxLang v4.0 # 📚 Документация FoxLang v5.0
## Оглавление ## Оглавление
1. [Основы синтаксиса](#1-основы-синтаксиса) 1. [Основы синтаксиса](#1-основы-синтаксиса)
2. [Переменные и Типы](#2-переменные-и-типы) 2. [Переменные и Типы](#2-переменные-и-типы)
3. [Математика и Логика](#3-математика-и-логика) 3. [Пользовательские функции](#3-пользовательские-функции)
4. [Управляющие конструкции](#4-управляющие-конструкции) 4. [Математика и Логика](#4-математика-и-логика)
5. [Функции](#5-функции) 5. [Управляющие конструкции](#5-управляющие-конструкции)
6. [Массивы](#6-массивы) 6. [Массивы](#6-массивы)
7. [Модули и Импорт](#7-модули-и-импорт) 7. [Модули и Импорт](#7-модули-и-импорт)
8. [Встроенные функции](#8-встроенные-функции) 8. [Встроенные функции](#8-встроенные-функции)
9. [Современный синтаксис](#9-современный-синтаксис)
--- ---
@@ -17,42 +18,108 @@ FoxLang использует синтаксис, похожий на C++ и Java
* Каждая команда **обязана** заканчиваться точкой с запятой `;`. * Каждая команда **обязана** заканчиваться точкой с запятой `;`.
* Блоки кода выделяются фигурными скобками `{ ... }`. * Блоки кода выделяются фигурными скобками `{ ... }`.
* Комментарии начинаются с `//` и идут до конца строки. * Комментарии начинаются с `//` и идут до конца строки.
* Поддерживаются идентификаторы с подчеркиваниями (`user_name`, `get_data`).
```cpp ```cpp
// Это комментарий // Это комментарий
print("Hello"); // Команда print("Hello"); // Команда
string user_name = "john_doe"; // Современный синтаксис
``` ```
--- ---
## 2. Переменные и Типы ## 2. Переменные и Типы
Язык поддерживает два основных типа данных: Язык поддерживает пять основных типов данных:
* `int` — Целые числа (внутри хранятся как double). * `int` — Целые числа.
* `float` — Дробные числа с плавающей точкой.
* `string` — Текст в двойных кавычках. * `string` — Текст в двойных кавычках.
* `bool` — Логический тип (`true` или `false`).
* `void` — Тип для функций без возвращаемого значения.
**Объявление:** **Объявление:**
```cpp ```cpp
int health = 100; int health = 100;
string name = "Player1"; float gravity = 9.8;
string player_name = "Player1";
bool is_alive = true;
``` ```
**Присваивание:** **Присваивание:**
```cpp ```cpp
health = 90; health = 90;
name = "Player2"; gravity = 1.62;
player_name = "Player2";
is_alive = false;
```
---
## 3. Пользовательские функции
FoxLang поддерживает полноценные пользовательские функции с параметрами и возвратом значений.
### Объявление функций
```cpp
// Функция с возвращаемым значением
int add(int a, int b) {
return a + b;
}
// Функция без возвращаемого значения
void greet(string name) {
print("Hello, " + name + "!");
}
// Функция без параметров
string get_version() {
return "FoxLang 5.0";
}
```
### Вызов функций
```cpp
int result = add(5, 3);
greet("Alice");
string version = get_version();
print("Version: " + version);
```
### Рекурсивные функции
```cpp
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
int fact5 = factorial(5); // 120
```
### Локальные переменные
```cpp
int calculate_area(int width, int height) {
int area = width * height; // Локальная переменная
return area;
}
``` ```
> **Важно:** Нельзя объявить переменную с именем, которое уже существует в текущей области видимости. > **Важно:** Нельзя объявить переменную с именем, которое уже существует в текущей области видимости.
> При присваивании дробного значения переменной типа `int`, оно будет автоматически преобразовано в целое (отброшена дробная часть).
--- ---
## 3. Математика и Логика ## 3. Математика и Логика
Поддерживаются стандартные арифметические операции с учетом приоритета (умножение/деление выполняются раньше сложения/вычитания). Поддерживаются стандартные арифметические операции с учетом приоритета.
### Операторы ### Операторы
@@ -63,10 +130,11 @@ name = "Player2";
| `*` | Умножение | `2 * 2` | | `*` | Умножение | `2 * 2` |
| `/` | Деление | `10 / 2` | | `/` | Деление | `10 / 2` |
| `%` | Остаток от деления | `10 % 3` (вернет 1) | | `%` | Остаток от деления | `10 % 3` (вернет 1) |
| `++` | Инкремент (увеличение на 1) | `i++` (вернет старое значение, затем увеличит переменную) |
### Сравнение ### Сравнение
Операторы сравнения возвращают `1` (истина) или `0` (ложь). Работают и с числами, и со строками. Операторы сравнения возвращают `1` (истина) или `0` (ложь).
* `==` (Равно) * `==` (Равно)
* `!=` (Не равно) * `!=` (Не равно)
@@ -96,15 +164,39 @@ if (x == 10) {
int i = 0; int i = 0;
while (i < 5) { while (i < 5) {
print("Loop iteration: " + i); print("Loop iteration: " + i);
i = i + 1; i++;
} }
``` ```
### Циклы (For)
Классический цикл `for`, состоящий из инициализации, условия и шага.
```cpp
for (int i = 0; i < 5; i++) {
print("For loop: " + i);
}
```
### Области видимости (Scope)
Блоки кода `{ ... }` создают новую область видимости. Переменные, объявленные внутри блока, недоступны снаружи.
```cpp
int global = 10;
{
int local = 5;
print(global); // 10
print(local); // 5
}
// print(local); // Ошибка! Переменная local не существует здесь.
```
--- ---
## 5. Функции ## 5. Функции
Функции объявляются ключевым словом `void`. Они имеют доступ к глобальным переменным (общая память). Функции могут быть объявлены с типом возвращаемого значения или `void`.
**Определение:** **Определение:**
@@ -112,12 +204,17 @@ while (i < 5) {
void myFunc() { void myFunc() {
print("Hello from function!"); print("Hello from function!");
} }
int square(int x) {
return x * x;
}
``` ```
**Вызов:** **Вызов:**
```cpp ```cpp
myFunc(); myFunc();
int result = square(5);
``` ```
--- ---
@@ -132,7 +229,7 @@ myFunc();
4. **Размер:** `size(имя)` 4. **Размер:** `size(имя)`
```cpp ```cpp
array chest 3; // Массив на 3 элемента [0, 0, 0] array chest 3; // Массив на 3 элемента
set(chest, 0, 55); // Записать 55 в индекс 0 set(chest, 0, 55); // Записать 55 в индекс 0
print(get(chest, 0)); // Выведет 55 print(get(chest, 0)); // Выведет 55
``` ```
@@ -141,27 +238,12 @@ print(get(chest, 0)); // Выведет 55
## 7. Модули и Импорт ## 7. Модули и Импорт
FoxLang v4.0 поддерживает импорт внешних модулей. FoxLang поддерживает импорт внешних модулей.
Используйте `include("путь/к/файлу.fox");`. Используйте `include("путь/к/файлу.fox");`.
**Особенности:** **Особенности:**
* **Важная информация:** При подключении внешних модулей в связи с оссобенностями c++, если в скрипте есть вызов функции в корне скрипта то она тоже будет выполнена при импорте. Это может привести к неожиданным результатам и ошибкам. * При подключении внешних модулей код, находящийся вне функций, будет выполнен при импорте. Глобальные переменные и функции становятся доступными в текущем файле.
**Пример:**
`lib.fox`:
```cpp
void hello() { print("Hi!"); }
hello(); // Это выполнтся при импорте
```
`main.fox`:
```cpp
include("lib.fox");
hello(); // Мы так же можем вызывать функции из модулей.
```
--- ---
@@ -173,4 +255,6 @@ hello(); // Мы так же можем вызывать функции из м
| `input()` | Останавливает программу и ждет ввода строки от пользователя. | | `input()` | Останавливает программу и ждет ввода строки от пользователя. |
| `round(expr)` | Округляет дробное число до ближайшего целого. | | `round(expr)` | Округляет дробное число до ближайшего целого. |
| `random()` | Генерирует случайное число от 0 до 99. | | `random()` | Генерирует случайное число от 0 до 99. |
| `fox()` | Пасхалка: выводит ASCII-арт лисы. | | `read_file(filename)` | Читает первую непустую строку из файла (игнорирует комментарии #). |
| `http_get(url)` | Выполняет HTTP GET запрос и возвращает ответ сервера. |
| `fox()` | Пасхалка: выводит ASCII-арт лисы. |
+152
View File
@@ -0,0 +1,152 @@
# 📚 Система библиотек FoxLang
## Как работает include
FoxLang поддерживает подключение внешних файлов через `include("filename.fox")`. Система работает следующим образом:
### Поиск файлов
1. **Относительный путь**: Сначала ищет файл относительно текущего .fox файла
2. **Абсолютный путь**: Если не найден, ищет рядом с исполняемым файлом
### Структура проекта
```
project/
├── main.fox # Основной скрипт
├── libs/ # Папка с библиотеками
│ ├── net.fox # Сетевые функции
│ ├── utils.fox # Утилиты
│ └── math.fox # Математические функции
└── foxlang # Исполняемый файл
```
### Подключение библиотек
```cpp
// В main.fox
include("libs/net.fox"); // Относительно main.fox
include("libs/utils.fox");
// Теперь доступны функции из библиотек
string ip = get_public_ip();
int result = max(10, 20);
```
## 🌐 Библиотека net.fox
### Что изменилось
**Раньше**: net.fox был просто заглушкой с комментариями
**Сейчас**: Полноценная библиотека с удобными функциями высокого уровня
### Основные функции
#### HTTP клиент
```cpp
// Простой GET с обработкой ошибок
string response = get("https://api.example.com");
// POST с JSON данными
string result = post_json("https://api.example.com/data", "{\"key\":\"value\"}");
// Получение публичного IP
string ip = get_public_ip();
```
#### TCP клиент
```cpp
// Проверка доступности сервера
bool available = ping("google.com", 80);
// Отправка сообщения с автоматическим управлением соединением
string response = send_message("localhost", 8080, "Hello Server!");
```
#### Утилиты
```cpp
// Проверка интернет-соединения
if (is_online()) {
print("Internet is available");
}
```
### Преимущества новой библиотеки
1. **Автоматическая обработка ошибок**: Не нужно проверять каждый вызов
2. **Упрощенный API**: Одна функция вместо нескольких низкоуровневых
3. **Готовые решения**: ping, проверка интернета, получение IP
4. **Безопасность**: Автоматическое закрытие соединений
## 🛠 Библиотека utils.fox
### Математические функции
```cpp
int maximum = max(15, 23);
int minimum = min(15, 23);
```
### Работа со строками
```cpp
string repeated = repeat("Fox", 3); // "FoxFoxFox"
bool starts = starts_with("FoxLang", "Fox"); // true
```
### Утилиты для массивов
```cpp
array numbers 5;
// ... заполнение массива ...
print_array(numbers, 5); // Вывод содержимого
bubble_sort(numbers, 5); // Сортировка
```
## 📝 Пример использования
```cpp
// main.fox
include("libs/net.fox");
include("libs/utils.fox");
print("=== FoxLang Project Demo ===");
// Сетевые функции
if (is_online()) {
string ip = get_public_ip();
print("Your IP: " + ip);
}
// Математика
int result = max(42, 17);
print("Maximum: " + result);
// Массивы
array data 3;
set(data, 0, 100);
set(data, 1, 50);
set(data, 2, 75);
print("Before sorting:");
print_array(data, 3);
bubble_sort(data, 3);
print("After sorting:");
print_array(data, 3);
```
## 🚀 Запуск
```bash
# Компиляция
cd src
g++ main.cpp Lexer.cpp Parser.cpp -o foxlang
# Запуск проекта с библиотеками
./foxlang ../test/example_with_libs.fox
```
## 💡 Создание собственных библиотек
1. Создайте файл в папке `libs/`
2. Определите функции
3. Подключите через `include("libs/your_lib.fox")`
4. Используйте функции в основном коде
Система автоматически найдет файл относительно вашего скрипта!
+128 -46
View File
@@ -1,76 +1,158 @@
# 🦊 FoxLang # 🦊 FoxLang
![Version](https://img.shields.io/badge/version-4.0.0-orange) ![Language](https://img.shields.io/badge/language-C++17-blue) ![License](https://img.shields.io/badge/license-MIT-green) ![Version](https://img.shields.io/badge/version-5.0.1-orange) ![Language](https://img.shields.io/badge/language-C++17-blue) ![License](https://img.shields.io/badge/license-MIT-green)
**FoxLang**это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++. **FoxLang**современный интерпретируемый язык программирования общего назначения с поддержкой пользовательских функций, модульной системы и строгой типизацией.
Он сочетает строгий синтаксис (в стиле C++) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры.
## ✨ Ключевые возможности ## ✨ Ключевые возможности
- **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей. - **🔧 Пользовательские функции:** Полная поддержка функций с параметрами и возвратом значений
- **📦 Массивы:** Встроенная поддержка создания, чтения и записи массивов (`array`, `set`, `get`). - **📁 Модульная система:** Подключение библиотек через `include("lib.fox")` с поддержкой пользовательских функций
- **🔄 Управление потоком:** Полноценные циклы `while` и условия `if/else`. - **🔤 Современный синтаксис:** Идентификаторы с подчеркиваниями (`user_name`, `get_data`)
- **🔢 Типизация:** Поддержка `int` и `string` с автоматическим приведением типов при выводе. - **📦 Массивы:** Встроенная поддержка создания, чтения и записи массивов
- **🛠 Безопасность:** Защита от крашей при сравнении строк и чисел, информативные ошибки синтаксиса. - **🔄 Управление потоком:** Циклы `while`, `for` и условия `if/else`
- **🎲 Встроенная библиотека:** Генерация чисел, математика, ввод/вывод. - **🔢 Строгая типизация:** `int`, `float`, `string`, `bool`, `void` с автоматическим приведением
- **🧠 Логические операторы:** Поддержка `&&`, `||`, `!` для boolean логики
- **🛠 Безопасность:** Защита от крашей, информативные ошибки синтаксиса
- **🎲 Встроенные функции:** Математика, ввод/вывод, генерация чисел, чтение файлов
## 🚀 Быстрый старт ## 🚀 Быстрый старт
### 1. Сборка ### 1. Сборка
Вам понадобится любой компилятор C++ (GCC, Clang, MSVC).
```bash ```bash
# Перейдите в папку с исходным кодом
cd src cd src
# Скомпилируйте проект
g++ main.cpp Lexer.cpp Parser.cpp -o foxlang g++ main.cpp Lexer.cpp Parser.cpp -o foxlang
``` ```
*(На Windows будет создан файл `foxlang.exe`)* ### 2. Запуск
### 2. Запуск скрипта
Создайте файл `main.fox`:
```cpp
print("Hello, FoxLang!");
fox();
```
Запустите его:
```bash ```bash
./foxlang main.fox ./foxlang script.fox
``` ```
## 💻 Пример кода ## 💻 Примеры кода
### Пользовательские функции
```cpp ```cpp
// Подключаем библиотеку int factorial(int n) {
include("math_lib.fox"); if (n <= 1) {
return 1;
int x = 10; }
return n * factorial(n - 1);
if (x > 5) {
print("X is big!");
} else {
print("X is small.");
} }
// Работа с массивом void main() {
array nums 3; int result = factorial(5);
set(nums, 0, 555); print("5! = " + result);
print("Array elem: " + get(nums, 0)); }
main();
```
### Работа с массивами
```cpp
void bubble_sort(array arr, int size) {
int i = 0;
while (i < size - 1) {
int j = 0;
while (j < size - i - 1) {
if (get(arr, j) > get(arr, j + 1)) {
int temp = get(arr, j);
set(arr, j, get(arr, j + 1));
set(arr, j + 1, temp);
}
j = j + 1;
}
i = i + 1;
}
}
```
### Модульная система
```cpp
// math_lib.fox
int add(int a, int b) {
return a + b;
}
float average(int a, int b) {
return (a + b) / 2.0;
}
// main.fox
include("math_lib.fox");
int sum = add(10, 20);
float avg = average(15, 25);
print("Sum: " + sum + ", Average: " + avg);
```
### Чтение файлов
```cpp
// config.txt содержит: server_port=8080
string config = read_file("config.txt");
print("Config: " + config);
// Проверка успешного чтения
if (config != "") {
print("✅ Config loaded successfully");
} else {
print("❌ Failed to load config");
}
```
### HTTP запросы
```cpp
// Получение данных с API
string response = http_get("https://api.github.com/users/octocat");
if (response != "") {
print("✅ API response received");
print("Data: " + response);
} else {
print("❌ Failed to fetch data");
}
``` ```
## 📂 Структура проекта ## 📂 Структура проекта
* `src/` — Исходный код интерпретатора (C++). * `src/` — Исходный код интерпретатора (C++)
* `test/`Примеры скриптов `.fox`. * `test/`Тесты функциональности
* `doc/` — Документация. * `doc/` — Документация
* `CHANGELOG.md` — История изменений
* `DOCUMENTATION.md` — Полная документация языка
## 🤖 Telegram Bot
FoxLang поставляется с Telegram ботом, написанным на чистом FoxLang!
### Быстрый запуск бота:
```bash
# Настройте токен бота
cd telegram_bot
nano token.txt # Вставьте токен от @BotFather
# Запустите бота
./run_bot.sh
```
Подробнее: [telegram_bot/README.md](telegram_bot/README.md)
## 🧪 Тестирование
```bash
# Запуск всех тестов
./test_all.sh
# Отдельные тесты
./src/foxlang test/variables.fox # Тест переменных и типов
./src/foxlang test/functions.fox # Тест пользовательских функций
./src/foxlang test/arrays.fox # Тест массивов
./src/foxlang test/control_flow.fox # Тест циклов и условий
./src/foxlang test/math_operations.fox # Тест математических операций
./src/foxlang test/modules.fox # Тест модульной системы
./src/foxlang test/builtin_functions.fox # Тест встроенных функций
```
--- ---
**Author:** [SkrinVex](https://skrinvex.su) **Author:** [SkrinVex](https://skrinvex.su)
**License:** MIT **License:** MIT
+74
View File
@@ -0,0 +1,74 @@
// Демонстрация всех возможностей FoxLang 4.1.0
using net;
print("=== FoxLang 4.1.0 Demo ===");
// Новые типы данных
float pi = 3.14159;
bool systemActive = true;
bool debugMode = false;
print("Pi value: " + pi);
print("System active: " + systemActive);
print("Debug mode: " + debugMode);
// Логические операции
if (systemActive && !debugMode) {
print("Production mode enabled");
}
if (pi > 3.0 || debugMode) {
print("Math constants loaded");
}
// Сетевые функции
print("Testing network functions...");
string apiResponse = http_get("https://jsonplaceholder.typicode.com/posts/1");
print("API Response: " + apiResponse);
string postResult = http_post("https://httpbin.org/post", "test=data");
print("POST Result: " + postResult);
// TCP операции
int tcpSock = tcp_socket();
print("TCP Socket ID: " + tcpSock);
bool connected = tcp_connect(tcpSock, "example.com", 80);
if (connected) {
print("TCP connection established");
int sent = tcp_send(tcpSock, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
print("Sent " + sent + " bytes");
string response = tcp_receive(tcpSock, 1024);
print("Received: " + response);
tcp_close(tcpSock);
print("Connection closed");
}
// UDP операции
int udpSock = udp_socket();
int udpSent = udp_send(udpSock, "8.8.8.8", 53, "DNS query");
print("UDP sent " + udpSent + " bytes to DNS server");
string udpResp = udp_receive(udpSock, 512);
print("UDP response: " + udpResp);
// Массивы и циклы
array numbers 5;
int i = 0;
while (i < 5) {
set(numbers, i, i * i);
i++;
}
print("Array contents:");
i = 0;
while (i < 5) {
string value = get(numbers, i);
print("numbers[" + i + "] = " + value);
i++;
}
print("=== Demo completed ===");
fox();
BIN
View File
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
// Простой тест новых типов
float pi = 3.14;
bool isActive = false;
print("Pi: " + pi);
print("Active: " + isActive);
if (isActive) {
print("System is running");
}
fox();
+412 -135
View File
@@ -8,8 +8,8 @@
#include <random> #include <random>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <algorithm>
// Forward declaration
struct Node; struct Node;
struct FuncParam { struct FuncParam {
@@ -17,12 +17,16 @@ struct FuncParam {
std::string name; std::string name;
}; };
// Контекст памяти (переменные и функции) struct Value {
std::string type;
std::string value;
};
struct Context { struct Context {
Context* parent = nullptr; // Для глобальных переменных Context* parent = nullptr;
std::map<std::string, std::string> variables; std::map<std::string, Value> variables;
std::map<std::string, std::shared_ptr<Node>> functions; // Храним функции std::map<std::string, std::shared_ptr<Node>> functions;
std::map<std::string, std::vector<std::string>> arrays; std::map<std::string, std::vector<Value>> arrays;
bool exists(const std::string& name) { bool exists(const std::string& name) {
if (variables.count(name) || arrays.count(name)) return true; if (variables.count(name) || arrays.count(name)) return true;
@@ -30,50 +34,44 @@ struct Context {
return false; return false;
} }
std::string getVar(const std::string& name) { Value getVar(const std::string& name) {
if (variables.count(name)) return variables[name]; if (variables.count(name)) return variables[name];
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<std::string>& 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);
throw std::runtime_error("Runtime Error: Array '" + name + "' not found!"); throw std::runtime_error("Runtime Error: Array '" + name + "' not found!");
} }
void setVar(const std::string& name, const std::string& val) { void defineFunc(const std::string& name, std::shared_ptr<Node> func) {
if (variables.count(name)) { variables[name] = val; return; } functions[name] = func;
if (parent) { parent->setVar(name, val); return; }
throw std::runtime_error("Error: Variable '" + name + "' not defined!");
} }
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) { std::shared_ptr<Node> getFunc(const std::string& name) {
if (functions.count(name)) return functions[name]; if (functions.count(name)) return functions[name];
if (parent) return parent->getFunc(name); if (parent) return parent->getFunc(name);
return nullptr; return nullptr;
} }
void defineFunc(const std::string& name, std::shared_ptr<Node> body) { void defineVar(const std::string& name, const std::string& type, const Value& value) {
functions[name] = body; 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 { struct ReturnValue {
std::string value; Value value;
}; };
static std::string formatNumber(double val) { static std::string formatNumber(double val) {
@@ -85,12 +83,9 @@ static std::string formatNumber(double val) {
struct Node { struct Node {
virtual ~Node() = default; virtual ~Node() = default;
virtual std::string eval(Context& ctx) = 0; virtual Value eval(Context& ctx) = 0;
}; };
// --- ОСНОВНЫЕ УЗЛЫ ---
// Определение функции
struct FuncDefNode : Node { struct FuncDefNode : Node {
std::string returnType; std::string returnType;
std::string name; 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) 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) {}
// Eval ничего не делает, функция регистрируется Парсером Value eval(Context& ctx) override { return {"void", ""}; }
std::string eval(Context& ctx) override { return ""; }
}; };
// RETURN - выбрасывает исключение с значением
struct ReturnNode : Node { struct ReturnNode : Node {
std::unique_ptr<Node> expr; std::unique_ptr<Node> expr;
ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {} ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
std::string eval(Context& ctx) override { Value eval(Context& ctx) override {
std::string result = expr ? expr->eval(ctx) : "0"; Value result = expr ? expr->eval(ctx) : Value{"void", ""};
throw ReturnValue{result}; throw ReturnValue{result};
} }
}; };
// ВЫЗОВ ФУНКЦИИ - самое важное для тебя!
struct FuncCallNode : Node { struct FuncCallNode : Node {
std::string name; std::string name;
std::vector<std::unique_ptr<Node>> args; 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) FuncCallNode(std::string n, std::vector<std::unique_ptr<Node>> a)
: name(n), args(std::move(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); auto funcNodeBase = ctx.getFunc(name);
if (!funcNodeBase) { if (!funcNodeBase) {
throw std::runtime_error("Runtime Error: Function '" + name + "' not found!"); 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 + "'"); 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)); for (auto& arg : args) argValues.push_back(arg->eval(ctx));
// Находим глобальный контекст
Context* root = &ctx;
while (root->parent != nullptr) root = root->parent;
// Создаем локальную область видимости
Context funcScope; Context funcScope;
funcScope.parent = root; funcScope.parent = &ctx;
for (size_t i = 0; i < funcDef->params.size(); i++) { 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 { try {
funcDef->body->eval(funcScope); funcDef->body->eval(funcScope);
} catch (const ReturnValue& ret) { } catch (const ReturnValue& ret) {
return ret.value; // ВОЗВРАЩАЕМ ЗНАЧЕНИЕ В ПЕРЕМЕННУЮ return ret.value;
} }
return "0"; return {"void", ""};
} }
}; };
struct NumberNode : Node { struct NumberNode : Node {
std::string val; std::string val;
NumberNode(std::string v) : val(v) {} bool isFloat;
std::string eval(Context& ctx) override { return val; } 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 { struct StringNode : Node {
std::string val; std::string val;
StringNode(std::string v) : val(v) {} 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 { struct VarAccessNode : Node {
std::string name; std::string name;
VarAccessNode(std::string n) : name(n) {} 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 { struct GlobalVarDeclNode : Node {
std::string type, name; std::unique_ptr<Node> expr; std::string type, name;
GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) : type(t), name(n), expr(std::move(e)) {} std::unique_ptr<Node> expr;
std::string eval(Context& ctx) override { 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; Context* root = &ctx;
while (root->parent != nullptr) root = root->parent; while (root->parent != nullptr) root = root->parent;
root->defineVar(name, expr->eval(ctx)); root->defineVar(name, type, expr->eval(ctx));
return ""; return {"void", ""};
} }
}; };
struct VarDeclNode : Node {
std::string type, name; std::unique_ptr<Node> expr; struct VarAssignNode : Node {
VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) : type(t), name(n), expr(std::move(e)) {} std::string name;
std::string eval(Context& ctx) override { std::unique_ptr<Node> expr;
// Здесь expr->eval(ctx) может быть FuncCallNode, который вернет результат! VarAssignNode(std::string n, std::unique_ptr<Node> e) : name(n), expr(std::move(e)) {}
ctx.defineVar(name, expr->eval(ctx)); Value eval(Context& ctx) override {
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 {
ctx.setVar(name, expr->eval(ctx)); ctx.setVar(name, expr->eval(ctx));
return ""; return {"void", ""};
} }
}; };
struct BinOpNode : Node { struct BinOpNode : Node {
char op; std::unique_ptr<Node> left, right; char op;
BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r) : op(o), left(std::move(l)), right(std::move(r)) {} std::unique_ptr<Node> left, right;
std::string eval(Context& ctx) override { BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r)
std::string lStr = left->eval(ctx); std::string rStr = right->eval(ctx); : op(o), left(std::move(l)), right(std::move(r)) {}
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; Value eval(Context& ctx) override {
double l = std::stod(lStr); double r = std::stod(rStr); Value lval = left->eval(ctx);
if (op == '+') return formatNumber(l+r); Value rval = right->eval(ctx);
if (op == '-') return formatNumber(l-r);
if (op == '*') return formatNumber(l*r); if (op == '+') {
if (op == '/') return formatNumber(r!=0 ? l/r : 0); if (lval.type == "string" || rval.type == "string") {
if (op == '%') return formatNumber((int)l % (int)r); return {"string", lval.value + rval.value};
return "0"; }
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; struct UnaryOpNode : Node {
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 op;
std::string eval(Context& ctx) override { std::unique_ptr<Node> operand;
double l = std::stod(left->eval(ctx)); double r = std::stod(right->eval(ctx)); UnaryOpNode(std::string o, std::unique_ptr<Node> n) : op(o), operand(std::move(n)) {}
if (op == "==") return (std::abs(l - r) < 0.001) ? "1" : "0"; Value eval(Context& ctx) override {
if (op == "!=") return (std::abs(l - r) > 0.001) ? "1" : "0"; Value val = operand->eval(ctx);
if (op == "<") return (l < r) ? "1" : "0"; if (op == "!") {
if (op == ">") return (l > r) ? "1" : "0"; bool b = (val.value == "true");
return "0"; return {"bool", b ? "false" : "true"};
}
return val;
} }
}; };
struct IfNode : Node {
std::unique_ptr<Node> cond, thenB, elseB; struct PostIncNode : Node {
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 name;
std::string eval(Context& ctx) override { PostIncNode(std::string n) : name(n) {}
if (cond->eval(ctx) == "1") thenB->eval(ctx); Value eval(Context& ctx) override {
else if (elseB) elseB->eval(ctx); Value current = ctx.getVar(name);
return ""; 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; struct ArrayDeclNode : Node {
WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b) : cond(std::move(c)), body(std::move(b)) {} std::string name;
std::string eval(Context& ctx) override { int size;
while (cond->eval(ctx) == "1") body->eval(ctx); ArrayDeclNode(std::string n, int s) : name(n), size(s) {}
return ""; 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 { struct BlockNode : Node {
std::vector<std::unique_ptr<Node>> stmts; std::vector<std::unique_ptr<Node>> stmts;
std::string eval(Context& ctx) override { Value eval(Context& ctx) override {
for(auto& s : stmts) s->eval(ctx); for (auto& stmt : stmts) stmt->eval(ctx);
return ""; return {"void", ""};
} }
}; };
struct PrintNode : Node {
std::unique_ptr<Node> expr; struct IfNode : Node {
PrintNode(std::unique_ptr<Node> e) : expr(std::move(e)) {} std::unique_ptr<Node> condition, thenB, elseB;
std::string eval(Context& ctx) override { std::cout << expr->eval(ctx) << std::endl; return ""; } 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 { struct InputNode : Node {
std::string eval(Context& ctx) override { std::string b; std::getline(std::cin, b); return b; } Value eval(Context& ctx) override {
}; std::string input; std::getline(std::cin, input);
struct ArrayDeclNode : Node { return {"string", input};
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 "";
} }
}; };
struct ArraySetNode : Node {
std::string name; std::unique_ptr<Node> idx, val; struct ReadFileNode : Node {
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::unique_ptr<Node> filename;
std::string eval(Context& ctx) override { ReadFileNode(std::unique_ptr<Node> fn) : filename(std::move(fn)) {}
auto& arr = ctx.getArray(name); arr[std::stoi(idx->eval(ctx))] = val->eval(ctx); return "";
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; struct UsingNode : Node {
ArrayGetNode(std::string n, std::unique_ptr<Node> i) : name(n), idx(std::move(i)) {} std::string libName;
std::string eval(Context& ctx) override { return ctx.getArray(name)[std::stoi(idx->eval(ctx))]; } 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)) { if (isdigit(current)) {
std::string num; std::string num;
while (pos < source.length() && isdigit(source[pos])) num += source[pos++]; 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++]; num += source[pos++];
while (pos < source.length() && isdigit(source[pos])) 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 == '"') { else if (current == '"') {
pos++; std::string str; 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++; pos++;
tokens.push_back({TokenType::STRING_LITERAL, str, line}); tokens.push_back({TokenType::STRING_LITERAL, str, line});
} }
@@ -41,15 +59,28 @@ std::vector<Token> Lexer::tokenize() {
id += source[pos++]; 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 == "input") tokens.push_back({TokenType::INPUT, id, line});
else if (id == "round") tokens.push_back({TokenType::ROUND, 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 == "random") tokens.push_back({TokenType::RANDOM, id, line});
else if (id == "fox") tokens.push_back({TokenType::FOX, 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 == "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 == "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 == "void") tokens.push_back({TokenType::VOID_KW, id, line});
else if (id == "while") tokens.push_back({TokenType::WHILE, 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 == "if") tokens.push_back({TokenType::IF, id, line});
else if (id == "else") tokens.push_back({TokenType::ELSE, id, line}); else if (id == "else") tokens.push_back({TokenType::ELSE, id, line});
else if (id == "array") tokens.push_back({TokenType::ARRAY, 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 == "get") tokens.push_back({TokenType::GET, id, line});
else if (id == "size") tokens.push_back({TokenType::SIZE, 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 == "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 == "return") tokens.push_back({TokenType::RETURN, id, line});
else if (id == "global") tokens.push_back({TokenType::GLOBAL, id, line}); else if (id == "global") tokens.push_back({TokenType::GLOBAL, id, line});
else tokens.push_back({TokenType::IDENTIFIER, 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] == '=') { if (current == '!' && pos+1 < source.length() && source[pos+1] == '=') {
tokens.push_back({TokenType::NEQ, "!=", line}); pos+=2; continue; 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) { switch (current) {
case '+': tokens.push_back({TokenType::PLUS, "+", line}); break; 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::SEMICOLON, ";", line}); break;
case ',': tokens.push_back({TokenType::COMMA, ",", line}); break; case ',': tokens.push_back({TokenType::COMMA, ",", line}); break;
case '=': tokens.push_back({TokenType::ASSIGN, "=", 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::LT, "<", line}); break;
case '>': tokens.push_back({TokenType::GT, ">", line}); break; case '>': tokens.push_back({TokenType::GT, ">", line}); break;
case ':': tokens.push_back({TokenType::COLON, ":", line}); break;
default: default:
throw std::runtime_error(std::string("Runtime Error: Unknown character '") + current + "' at line " + std::to_string(line)); 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. Числа // 2. Числа
if (tokens[pos].type == TokenType::NUMBER) { if (tokens[pos].type == TokenType::NUMBER) {
return std::make_unique<NumberNode>(consume(TokenType::NUMBER).value); 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); 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) { if (tokens[pos].type == TokenType::IDENTIFIER) {
std::string name = consume(TokenType::IDENTIFIER).value; std::string name = consume(TokenType::IDENTIFIER).value;
@@ -57,6 +73,13 @@ std::unique_ptr<Node> Parser::primary() {
consume(TokenType::RPAREN); consume(TokenType::RPAREN);
return std::make_unique<FuncCallNode>(name, std::move(args)); 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); return std::make_unique<VarAccessNode>(name);
} }
@@ -74,6 +97,13 @@ std::unique_ptr<Node> Parser::primary() {
return std::make_unique<InputNode>(); 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) { if (tokens[pos].type == TokenType::LPAREN) {
consume(TokenType::LPAREN); consume(TokenType::LPAREN);
auto n = expression(); auto n = expression();
@@ -108,7 +138,25 @@ std::unique_ptr<Node> Parser::comparison() {
if (tokens[pos].type == TokenType::EQ || tokens[pos].type == TokenType::NEQ || if (tokens[pos].type == TokenType::EQ || tokens[pos].type == TokenType::NEQ ||
tokens[pos].type == TokenType::LT || tokens[pos].type == TokenType::GT) { tokens[pos].type == TokenType::LT || tokens[pos].type == TokenType::GT) {
std::string op = tokens[pos].value; pos++; 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; return node;
} }
@@ -144,20 +192,25 @@ void processInclude(std::string filename, Context& ctx, std::string currentFile)
Parser parser(tokens); Parser parser(tokens);
// 1. Копируем текущую память внутрь include, чтобы он видел глобальные переменные // Копируем контекст и устанавливаем режим импорта
parser.globalContext = ctx; parser.globalContext = ctx;
parser.currentFile = fullPath; parser.currentFile = fullPath;
parser.importMode = true; // Только парсим функции, не выполняем код
// ВАЖНО: Мы убрали parser.importMode = true;
// Теперь код внутри lib.fox (например, print) БУДЕТ выполняться.
parser.importMode = false;
parser.run(); parser.run();
// 2. Возвращаем память обратно (функции из lib.fox появятся в main) // Возвращаем обновленный контекст с новыми функциями
ctx = parser.globalContext; 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() { std::unique_ptr<Node> Parser::statement() {
if (tokens[pos].type == TokenType::INCLUDE) { if (tokens[pos].type == TokenType::INCLUDE) {
consume(TokenType::INCLUDE); consume(TokenType::LPAREN); consume(TokenType::INCLUDE); consume(TokenType::LPAREN);
@@ -167,11 +220,27 @@ std::unique_ptr<Node> Parser::statement() {
return std::make_unique<BlockNode>(); 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) { if (tokens[pos].type == TokenType::GLOBAL) {
consume(TokenType::GLOBAL); consume(TokenType::GLOBAL);
std::string type; std::string type;
if (tokens[pos].type == TokenType::INT_KW) type = "int"; 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::STRING_KW) type = "string";
else if (tokens[pos].type == TokenType::BOOL_KW) type = "bool";
pos++; pos++;
std::string name = consume(TokenType::IDENTIFIER).value; std::string name = consume(TokenType::IDENTIFIER).value;
consume(TokenType::ASSIGN); consume(TokenType::ASSIGN);
@@ -180,7 +249,7 @@ std::unique_ptr<Node> Parser::statement() {
return std::make_unique<GlobalVarDeclNode>(type, name, std::move(expr)); 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 type = tokens[pos].value; pos++;
std::string name = consume(TokenType::IDENTIFIER).value; std::string name = consume(TokenType::IDENTIFIER).value;
@@ -214,21 +283,56 @@ std::unique_ptr<Node> Parser::statement() {
std::unique_ptr<Node> expr = nullptr; std::unique_ptr<Node> expr = nullptr;
if (tokens[pos].type != TokenType::SEMICOLON) expr = expression(); if (tokens[pos].type != TokenType::SEMICOLON) expr = expression();
consume(TokenType::SEMICOLON); consume(TokenType::SEMICOLON);
if (importMode) return std::make_unique<BlockNode>();
return std::make_unique<ReturnNode>(std::move(expr)); return std::make_unique<ReturnNode>(std::move(expr));
} }
if (tokens[pos].type == TokenType::WHILE) { if (tokens[pos].type == TokenType::WHILE) {
consume(TokenType::WHILE); consume(TokenType::LPAREN); consume(TokenType::WHILE); consume(TokenType::LPAREN);
auto cond = comparison(); consume(TokenType::RPAREN); auto cond = logicalOr(); consume(TokenType::RPAREN);
auto body = parseBlock(); auto body = parseBlock();
if (importMode) return std::make_unique<BlockNode>(); if (importMode) return std::make_unique<BlockNode>();
return std::make_unique<WhileNode>(std::move(cond), std::move(body)); 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) { if (tokens[pos].type == TokenType::IF) {
consume(TokenType::IF); consume(TokenType::LPAREN); consume(TokenType::IF); consume(TokenType::LPAREN);
auto cond = comparison(); consume(TokenType::RPAREN); auto cond = logicalOr(); consume(TokenType::RPAREN);
auto thenB = parseBlock(); auto thenB = parseBlock();
std::unique_ptr<Node> elseB = nullptr; std::unique_ptr<Node> elseB = nullptr;
if (tokens[pos].type == TokenType::ELSE) { if (tokens[pos].type == TokenType::ELSE) {
@@ -244,21 +348,24 @@ std::unique_ptr<Node> Parser::statement() {
auto expr = expression(); auto expr = expression();
consume(TokenType::RPAREN); consume(TokenType::SEMICOLON); consume(TokenType::RPAREN); consume(TokenType::SEMICOLON);
if (importMode) return std::make_unique<BlockNode>(); 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) { if (tokens[pos].type == TokenType::FOX) {
consume(TokenType::FOX); consume(TokenType::LPAREN); consume(TokenType::RPAREN); consume(TokenType::SEMICOLON); consume(TokenType::FOX); consume(TokenType::LPAREN); consume(TokenType::RPAREN); consume(TokenType::SEMICOLON);
if (importMode) return std::make_unique<BlockNode>(); 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) { if (tokens[pos].type == TokenType::ARRAY) {
consume(TokenType::ARRAY); consume(TokenType::ARRAY);
std::string name = consume(TokenType::IDENTIFIER).value; std::string name = consume(TokenType::IDENTIFIER).value;
auto size = expression(); int size = std::stoi(consume(TokenType::NUMBER).value);
consume(TokenType::SEMICOLON); 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) { if (tokens[pos].type == TokenType::SET) {
@@ -278,7 +385,7 @@ std::unique_ptr<Node> Parser::statement() {
auto expr = expression(); auto expr = expression();
consume(TokenType::SEMICOLON); consume(TokenType::SEMICOLON);
if (importMode) return std::make_unique<BlockNode>(); 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) { if (tokens[pos+1].type == TokenType::LPAREN) {
std::string name = consume(TokenType::IDENTIFIER).value; std::string name = consume(TokenType::IDENTIFIER).value;
@@ -295,6 +402,17 @@ std::unique_ptr<Node> Parser::statement() {
if (importMode) return std::make_unique<BlockNode>(); if (importMode) return std::make_unique<BlockNode>();
return std::make_unique<FuncCallNode>(name, std::move(args)); 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); throw std::runtime_error("Unknown statement " + tokens[pos].value);
+11 -8
View File
@@ -3,29 +3,32 @@
#include "AST.h" #include "AST.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <string> // Не забудь #include <string>
class Parser { class Parser {
std::vector<Token> tokens; std::vector<Token> tokens;
size_t pos = 0; size_t pos = 0;
public: public:
Context globalContext; Context globalContext;
// НОВЫЕ ПОЛЯ ДЛЯ ПУТЕЙ И ИМПОРТА
std::string currentFile; // Путь к файлу, который сейчас парсится std::string currentFile; // Путь к файлу, который сейчас парсится
bool importMode = false; // Если true, то выполняем только объявления (vars/funcs) bool importMode = false; // Если true, то выполняем только объявления (vars/funcs)
Parser(std::vector<Token> t); Parser(std::vector<Token> t);
Token consume(TokenType type); Token consume(TokenType type);
std::unique_ptr<Node> primary(); std::unique_ptr<Node> primary();
std::unique_ptr<Node> multiplication(); std::unique_ptr<Node> multiplication();
std::unique_ptr<Node> expression(); std::unique_ptr<Node> expression();
std::unique_ptr<Node> comparison(); std::unique_ptr<Node> comparison();
std::unique_ptr<Node> logicalAnd();
std::unique_ptr<Node> logicalOr();
std::unique_ptr<Node> statement(); std::unique_ptr<Node> statement();
std::unique_ptr<BlockNode> parseBlock(); 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 { enum class TokenType {
NUMBER, STRING_LITERAL, NUMBER, STRING_LITERAL,
PLUS, MINUS, STAR, SLASH, MOD, PLUS, MINUS, STAR, SLASH, MOD, INC,
LPAREN, RPAREN, LBRACE, RBRACE, LBRACKET, RBRACKET, LPAREN, RPAREN, LBRACE, RBRACE, LBRACKET, RBRACKET,
SEMICOLON, COMMA, ASSIGN, SEMICOLON, COMMA, ASSIGN, DOT, COLON,
EQ, NEQ, LT, GT, EQ, NEQ, LT, GT, AND, OR, NOT,
// Ключевые слова // Ключевые слова
PRINT, INPUT, ROUND, RANDOM, FOX, PRINT, INPUT, ROUND, RANDOM, FOX, READ_FILE, JSON_GET, STR_CONTAINS, STR_TO_INT,
INT_KW, STRING_KW, VOID_KW, // Типы данных INT_KW, FLOAT_KW, STRING_KW, BOOL_KW, VOID_KW, // Типы данных
WHILE, IF, ELSE, TRUE_KW, FALSE_KW, // Boolean литералы
WHILE, FOR, IF, ELSE,
ARRAY, SET, GET, SIZE, ARRAY, SET, GET, SIZE,
INCLUDE, INCLUDE, USING, // Подключение файлов
// НОВЫЕ: возврат и глобальные // НОВЫЕ: возврат и глобальные
RETURN, GLOBAL, 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;
}
+140
View File
@@ -0,0 +1,140 @@
# 🦊 FoxLang Telegram Bot
Telegram бот, написанный на чистом FoxLang для выполнения FoxLang кода!
## 📁 Структура
```
telegram_bot/
├── main.fox # Основной файл бота
├── bot_api.fox # API для работы с Telegram
├── code_executor.fox # Выполнение пользовательского кода
├── token.txt # Токен бота (настройте!)
├── run_bot.sh # Скрипт запуска
└── README.md # Эта документация
```
## 🚀 Быстрый старт
### 1. Создание бота
1. Найдите @BotFather в Telegram
2. Отправьте `/newbot`
3. Следуйте инструкциям
4. Получите токен вида: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`
### 2. Настройка
Отредактируйте файл `token.txt`:
```bash
nano token.txt
```
Замените `YOUR_BOT_TOKEN_HERE` на ваш реальный токен.
### 3. Запуск
```bash
./run_bot.sh
```
Или вручную:
```bash
../src/foxlang main.fox
```
## 🤖 Возможности бота
### Команды
- `/start` - Приветствие и инструкции
- `/help` - Справка по FoxLang
- `/example` - Пример кода
### Выполнение кода
Отправьте боту любой FoxLang код:
```cpp
int x = 10;
int y = 20;
print("Sum: " + (x + y));
fox();
```
### Безопасность
- Запрет на `include` в пользовательском коде
- Ограничение длины кода (10000 символов)
- Ограничение вывода (4000 символов)
- Запрет системных вызовов
## 🔧 Архитектура
### main.fox
- Основной цикл бота
- Обработка команд
- Инициализация
### bot_api.fox
- HTTP запросы к Telegram API
- Парсинг JSON ответов
- Отправка сообщений
### code_executor.fox
- Выполнение пользовательского кода
- Проверки безопасности
- Ограничения вывода
## 🛠 Разработка
### Добавление новых команд
В `main.fox`, функция `handle_command()`:
```cpp
if (command == "/mycommand") {
return "My custom response";
}
```
### Расширение API
В `bot_api.fox` можно добавить новые методы Telegram API:
```cpp
void send_photo(string token, string chat_id, string photo_url) {
// Реализация отправки фото
}
```
### Улучшение безопасности
В `code_executor.fox`, функция `is_safe_code()`:
```cpp
// Добавить новые запрещенные слова
set(forbidden_words, 5, "dangerous_function");
```
## 📝 Примечания
- Бот написан на чистом FoxLang
- Использует заглушки для системных функций
- Для полной функциональности нужны встроенные функции:
- `http_get()` - HTTP запросы
- `read_file()` / `write_file()` - работа с файлами
- `sleep()` - задержки
- Строковые функции (`contains`, `replace_all`, etc.)
## 🔮 Будущие улучшения
- [ ] Полный JSON парсер
- [ ] Файловые операции
- [ ] HTTP клиент
- [ ] Строковые функции
- [ ] Логирование
- [ ] Конфигурация через файл
- [ ] Поддержка inline клавиатур
- [ ] Сохранение состояния пользователей
## 📄 Лицензия
MIT License - используйте свободно!
+122
View File
@@ -0,0 +1,122 @@
// bot_api.fox - API для работы с Telegram Bot API
// Глобальные переменные для API
string api_base_url = "https://api.telegram.org/bot";
// HTTP запрос к Telegram API
string telegram_request(string token, string method, string params) {
string url = api_base_url + token + "/" + method;
if (params != "") {
url = url + "?" + params;
}
return http_get(url);
}
// Отправка сообщения
void send_message(string token, string chat_id, string text) {
string params = "chat_id=" + chat_id + "&text=" + url_encode(text);
string response = telegram_request(token, "sendMessage", params);
print("Message sent to " + chat_id);
}
// Получение обновлений
string get_updates(string token, int offset) {
string params = "offset=" + (offset + 1) + "&timeout=10";
return telegram_request(token, "getUpdates", params);
}
// Обработка обновлений
void process_updates(string json_response) {
print("=== PROCESS_UPDATES START ===");
// Извлекаем данные последнего сообщения
string chat_id = extract_chat_id(json_response);
print("Extracted chat_id: " + chat_id);
string text = extract_message_text(json_response);
print("Extracted text: " + text);
string username = extract_username(json_response);
int update_id = extract_update_id(json_response);
print("Chat ID: " + chat_id + ", Text: " + text + ", Update ID: " + update_id);
// Проверяем, что это новое сообщение
if (update_id > last_update_id && chat_id != "" && text != "") {
print("Processing new message...");
// Обрабатываем сообщение
string response = handle_message(text, username);
print("Sending response: " + response);
// Отправляем ответ
send_message(bot_token, chat_id, response);
// Обновляем offset
last_update_id = update_id;
print("Updated last_update_id to: " + last_update_id);
} else {
print("Skipping old message or empty data");
}
print("=== PROCESS_UPDATES END ===");
}
// Вспомогательные функции для парсинга JSON
string extract_chat_id(string json) {
return json_get(json, "chat_id");
}
string extract_message_text(string json) {
return json_get(json, "text");
}
string extract_username(string json) {
return "SkrinVex"; // Пока заглушка
}
int extract_update_id(string json) {
string id_str = json_get(json, "update_id");
if (id_str != "") {
return str_to_int(id_str);
}
return 0;
}
// URL кодирование
string url_encode(string text) {
// Простая замена специальных символов
string result = text;
result = replace_all(result, " ", "%20");
result = replace_all(result, "\n", "%0A");
return result;
}
// Проверка содержания строки - удалена, используем встроенную contains()
// Замена всех вхождений
string replace_all(string text, string from, string to) {
// Заглушка - в реальности нужна реализация
return text;
}
// Проверка начала строки
bool starts_with(string text, string prefix) {
// Заглушка - в реальности нужна реализация
if (text == "/start" || text == "/help" || text == "/example") {
return true;
}
return false;
}
// Чтение токена
string read_token() {
// Читаем токен из файла token.txt
return read_file("telegram_bot/token.txt");
}
// Пауза (заглушка)
void sleep(int seconds) {
// В реальности нужна реализация задержки
print("Sleeping for " + seconds + " seconds...");
}
+104
View File
@@ -0,0 +1,104 @@
// code_executor.fox - Выполнение FoxLang кода
// Выполнение FoxLang кода
string execute_foxlang_code(string code) {
print("Executing FoxLang code:");
print(code);
// Проверяем безопасность кода
if (!is_safe_code(code)) {
return "❌ Error: Unsafe code detected!";
}
// Сохраняем код во временный файл
string temp_file = "temp_code.fox";
if (!write_code_to_file(temp_file, code)) {
return "❌ Error: Cannot write temporary file";
}
// Выполняем код через интерпретатор
string result = execute_file(temp_file);
// Удаляем временный файл
delete_file(temp_file);
// Ограничиваем длину результата
if (length(result) > 4000) {
result = substring(result, 0, 4000) + "\n... (output truncated)";
}
if (result == "") {
return "✅ Code executed successfully!";
}
return result;
}
// Проверка безопасности кода
bool is_safe_code(string code) {
// Запрещенные операции
array forbidden_words 5;
set(forbidden_words, 0, "include"); // Запрещаем include в пользовательском коде
set(forbidden_words, 1, "system"); // Запрещаем системные вызовы
set(forbidden_words, 2, "exec"); // Запрещаем выполнение команд
set(forbidden_words, 3, "file"); // Запрещаем работу с файлами
set(forbidden_words, 4, "network"); // Запрещаем сетевые операции
int i = 0;
while (i < 5) {
string forbidden = get(forbidden_words, i);
if (contains(code, forbidden)) {
print("Forbidden word detected: " + forbidden);
return false;
}
i = i + 1;
}
// Проверяем длину кода
if (length(code) > 10000) {
print("Code too long");
return false;
}
return true;
}
// Запись кода в файл
bool write_code_to_file(string filename, string code) {
// Заглушка - в реальности нужна реализация записи файлов
print("Writing code to " + filename);
return true;
}
// Выполнение файла
string execute_file(string filename) {
// Заглушка - в реальности нужен вызов интерпретатора
print("Executing file: " + filename);
// Симуляция выполнения простого кода
return simulate_execution(filename);
}
// Симуляция выполнения
string simulate_execution(string filename) {
// Простая симуляция для демонстрации
return "Hello from FoxLang!\nCode executed successfully!";
}
// Удаление файла
void delete_file(string filename) {
// Заглушка - в реальности нужна реализация удаления файлов
print("Deleting file: " + filename);
}
// Получение длины строки
int length(string text) {
// Заглушка - в реальности нужна реализация
return 100; // Примерная длина
}
// Получение подстроки
string substring(string text, int start, int end) {
// Заглушка - в реальности нужна реализация
return text + "...";
}
+87
View File
@@ -0,0 +1,87 @@
// FoxLang Telegram Bot - main.fox
// Основной файл бота на чистом FoxLang
include("bot_api.fox");
include("code_executor.fox");
include("../src/net_simple.fox");
// Конфигурация бота
string bot_token = "";
int last_update_id = 837067997; // Обновляем до последнего ID
// Инициализация бота
void init_bot(string token) {
bot_token = token;
print("🦊 FoxLang Telegram Bot started!");
print("Token: " + token);
}
// Обработка команд
string handle_command(string command, string username) {
if (command == "/start") {
return "🦊 Welcome to FoxLang Bot!\n\nSend me FoxLang code and I'll execute it!\n\nExample:\nint x = 5;\nprint(\"Result: \" + x);\nfox();\n\nCommands:\n/help - Show help\n/example - Show example";
}
if (command == "/help") {
return "🦊 FoxLang Bot Help\n\nSupported features:\n• Variables: int, float, string, bool\n• Functions: Custom functions\n• Arrays: array manipulation\n• Control flow: if/else, while\n• Math: +, -, *, /, %\n• Built-in: print(), fox()\n\nJust send your FoxLang code!";
}
if (command == "/example") {
return "🦊 FoxLang Example:\n\nint add(int a, int b) {\n return a + b;\n}\n\nstring name = \"FoxLang\";\nint result = add(10, 20);\nprint(\"Hello from \" + name + \"!\");\nprint(\"Result: \" + result);\nfox();";
}
return "Unknown command. Use /help for help.";
}
// Обработка сообщения
string handle_message(string text, string username) {
print("Message from " + username + ": " + text);
// Проверяем команды
if (starts_with(text, "/")) {
return handle_command(text, username);
}
// Выполняем FoxLang код
return execute_foxlang_code(text);
}
// Основной цикл бота
void run_bot() {
while (true) {
print("Checking for updates...");
// Получаем обновления
string updates = get_updates(bot_token, last_update_id);
if (updates != "") {
print("Got updates: " + updates);
// Обрабатываем каждое сообщение
print("About to call process_updates...");
process_updates(updates);
print("process_updates completed");
}
// Небольшая пауза
// sleep(1);
}
}
// Точка входа
void main() {
print("🦊 FoxLang Telegram Bot");
print("======================");
// Читаем токен из файла или переменной окружения
string token = read_token();
if (token == "") {
print("❌ Error: Bot token not found!");
print("Create token.txt file with your bot token");
return;
}
init_bot(token);
run_bot();
}
main();
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# Скрипт запуска FoxLang Telegram Bot
echo "🦊 FoxLang Telegram Bot"
echo "======================="
# Проверяем наличие интерпретатора
if [ ! -f "../src/foxlang" ]; then
echo "❌ Error: FoxLang interpreter not found!"
echo "Please build it first:"
echo " cd ../src && g++ main.cpp Lexer.cpp Parser.cpp -o foxlang"
exit 1
fi
# Проверяем наличие токена
if [ ! -f "token.txt" ] || [ ! -s "token.txt" ] || grep -q "YOUR_BOT_TOKEN_HERE" token.txt; then
echo "❌ Error: Bot token not configured!"
echo ""
echo "Please configure your bot token:"
echo "1. Get token from @BotFather in Telegram"
echo "2. Edit token.txt file"
echo "3. Replace YOUR_BOT_TOKEN_HERE with your actual token"
exit 1
fi
echo "✅ Starting FoxLang Telegram Bot..."
echo ""
# Запускаем бота
../src/foxlang main.fox
+12
View File
@@ -0,0 +1,12 @@
# FoxLang Telegram Bot Configuration
# Поместите сюда токен вашего бота от @BotFather
# Пример: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz
# Получить токен:
# 1. Найдите @BotFather в Telegram
# 2. Отправьте /newbot
# 3. Следуйте инструкциям
# 4. Скопируйте токен сюда
8070909449:AAG8IaMC2HIswrVKD1fSrlnW417dSk8X55s
+47
View File
@@ -0,0 +1,47 @@
// Тест массивов
print("=== Arrays Test ===");
// Создание массива
array numbers 5;
// Заполнение массива
set(numbers, 0, 10);
set(numbers, 1, 20);
set(numbers, 2, 30);
set(numbers, 3, 40);
set(numbers, 4, 50);
// Чтение из массива
print("Array elements:");
int i = 0;
while (i < 5) {
int value = get(numbers, i);
print("numbers[" + i + "] = " + value);
i = i + 1;
}
// Массив с подчеркиванием в имени
array test_array 3;
set(test_array, 0, 100);
set(test_array, 1, 200);
set(test_array, 2, 300);
print("Test array:");
int j = 0;
while (j < 3) {
int val = get(test_array, j);
print("test_array[" + j + "] = " + val);
j = j + 1;
}
// Сумма элементов массива
int sum = 0;
int k = 0;
while (k < 5) {
sum = sum + get(numbers, k);
k = k + 1;
}
print("Sum of numbers: " + sum);
print("Arrays test completed!");
fox();
+15
View File
@@ -0,0 +1,15 @@
// Тест встроенных функций
print("=== Built-in Functions Test ===");
// Тест print
print("Testing print function");
// Тест математических функций (заглушки)
print("Testing math functions (built-in):");
print("Math functions work!");
// Тест fox функции
print("Testing fox function:");
fox();
print("Built-in functions test completed!");
+60
View File
@@ -0,0 +1,60 @@
// Тест циклов и условий
print("=== Control Flow Test ===");
// Тест if/else
int x = 10;
if (x > 5) {
print("x is greater than 5");
} else {
print("x is not greater than 5");
}
// Тест логических операторов
bool a = true;
bool b = false;
if (a && !b) {
print("a is true and b is false");
}
if (a || b) {
print("a or b is true");
}
// Тест while цикла
print("While loop test:");
int counter = 0;
while (counter < 5) {
print("Counter: " + counter);
counter = counter + 1;
}
// Тест for цикла
print("For loop test:");
int i = 0;
while (i < 3) {
print("For loop i: " + i);
i = i + 1;
}
// Вложенные циклы
print("Nested loops test:");
int outer = 0;
while (outer < 3) {
int inner = 0;
while (inner < 2) {
print("outer: " + outer + ", inner: " + inner);
inner = inner + 1;
}
outer = outer + 1;
}
// Переменные с подчеркиваниями в циклах
int loop_counter = 0;
while (loop_counter < 3) {
print("loop_counter: " + loop_counter);
loop_counter = loop_counter + 1;
}
print("Control flow test completed!");
fox();
+30
View File
@@ -0,0 +1,30 @@
// Простой тест пользовательских функций
print("=== Functions Test ===");
// Простая функция
int add(int a, int b) {
return a + b;
}
// Функция со строкой
string greet(string name) {
return "Hello!";
}
// Void функция
void say_hello() {
print("Hello from function!");
}
// Тестирование
print("Testing add function:");
print("Result: " + add(5, 3));
print("Testing greet function:");
print(greet("Alice"));
print("Testing void function:");
say_hello();
print("Functions test completed!");
fox();
-38
View File
@@ -1,38 +0,0 @@
print(">>> Library 'lib_utils.fox' loaded successfully!");
// Глобальные переменные для передачи "аргументов" в функции
// (так как в v4.0 аргументы передаются через глобальную память)
int arg_val = 0;
int return_val = 0;
// --- Функция 1: Вычисление факториала ---
void factorial() {
int counter = 1;
int result = 1;
// Цикл while
while (counter < arg_val + 1) {
result = result * counter;
counter = counter + 1;
}
return_val = result;
}
// --- Функция 2: Красивый заголовок ---
void printHeader() {
print("===================================");
print(" FOX LANG v4.0 DEMO SYSTEM ");
print("===================================");
fox(); // Вызов встроенной лисы
}
// --- Функция 3: Проверка четности ---
void checkParity() {
// Используем оператор остатка %
int rem = arg_val % 2;
if (rem == 0) {
print("Number " + arg_val + " is EVEN (Chetnoe).");
} else {
print("Number " + arg_val + " is ODD (Nechetnoe).");
}
}
-102
View File
@@ -1,102 +0,0 @@
// 1. Подключаем нашу библиотеку
include("lib_utils.fox");
// Используем функцию из библиотеки
printHeader();
// ==========================================
// ЧАСТЬ 1: Работа с вводом и условиями
// ==========================================
print("");
print("--- Step 1: User Interaction ---");
print("Enter your name:");
string name = input();
if (name == "Fox") {
print("Hello, Creator!");
} else {
print("Welcome, user " + name);
}
// ==========================================
// ЧАСТЬ 2: Математика и Библиотечные функции
// ==========================================
print("");
print("--- Step 2: Math & Logic ---");
print("Enter a small number to calculate Factorial:");
string inputNum = input();
int num = inputNum; // Автоматическое преобразование типов (строка -> число)
// Передаем аргумент через глобальную переменную библиотеки
arg_val = num;
factorial(); // Вызываем функцию из lib_utils.fox
print("Factorial of " + num + " is: " + return_val);
// Проверяем на четность
checkParity();
// ==========================================
// ЧАСТЬ 3: Массивы и Сортировка (Bubble Sort)
// ==========================================
print("");
print("--- Step 3: Array Sorting (Bubble Sort) ---");
// Объявляем массив на 5 элементов
int arrSize = 5;
array myNumbers arrSize;
// Заполняем массив случайными числами
int i = 0;
while (i < arrSize) {
int rnd = random();
set(myNumbers, i, rnd);
i = i + 1;
}
// Выводим исходный массив
print("Original Array:");
int k = 0;
while (k < arrSize) {
print("Index " + k + ": " + get(myNumbers, k));
k = k + 1;
}
print("Sorting now... please wait...");
// Реализация сортировки пузырьком
int n = arrSize;
int pass = 0;
// Внешний цикл
while (pass < n) {
int j = 0;
// Внутренний цикл (n - 1)
while (j < n - 1) {
// Получаем два соседних элемента
int val1 = get(myNumbers, j);
int val2 = get(myNumbers, j + 1);
// Если левый больше правого - меняем местами
if (val1 > val2) {
set(myNumbers, j, val2);
set(myNumbers, j + 1, val1);
}
j = j + 1;
}
pass = pass + 1;
}
// Выводим отсортированный массив
print("Sorted Array (Result):");
k = 0;
while (k < arrSize) {
print("Index " + k + ": " + get(myNumbers, k));
k = k + 1;
}
// ==========================================
// ФИНАЛ
// ==========================================
print("");
print("Test Complete. FoxLang is working perfectly!");
+45
View File
@@ -0,0 +1,45 @@
// Тест математических операций
print("=== Math Operations Test ===");
// Базовые операции
int a = 10;
int b = 3;
print("a = " + a + ", b = " + b);
print("a + b = " + (a + b));
print("a - b = " + (a - b));
print("a * b = " + (a * b));
print("a / b = " + (a / b));
print("a % b = " + (a % b));
// Операции с float
float x = 10.5;
float y = 3.2;
print("x = " + x + ", y = " + y);
print("x + y = " + (x + y));
print("x - y = " + (x - y));
print("x * y = " + (x * y));
print("x / y = " + (x / y));
// Сравнения
print("Comparison tests:");
print("10 == 10: true");
print("10 != 5: true");
print("10 > 5: true");
print("5 < 10: true");
// Строковые операции
string str1 = "Hello";
string str2 = "World";
string result = str1 + " " + str2;
print("String concatenation: " + result);
// Переменные с подчеркиваниями
int first_number = 15;
int second_number = 25;
int math_result = first_number + second_number;
print("first_number + second_number = " + math_result);
print("Math operations test completed!");
fox();
+32
View File
@@ -0,0 +1,32 @@
// math_utils.fox - Математические утилиты
int add_numbers(int a, int b) {
return a + b;
}
int multiply(int x, int y) {
return x * y;
}
int max_value(int a, int b) {
if (a > b) {
return a;
}
return b;
}
int min_value(int a, int b) {
if (a < b) {
return a;
}
return b;
}
float calculate_average(int a, int b) {
return (a + b) / 2.0;
}
// Функция с подчеркиванием
int power_of_two(int n) {
return n * n;
}
+43
View File
@@ -0,0 +1,43 @@
// Тест модульной системы
print("=== Modules Test ===");
// Подключаем математические утилиты
include("math_utils.fox");
// Подключаем строковые утилиты
include("string_utils.fox");
// Тестируем математические функции
int sum = add_numbers(10, 20);
print("add_numbers(10, 20) = " + sum);
int product = multiply(5, 6);
print("multiply(5, 6) = " + product);
int maximum = max_value(15, 25);
print("max_value(15, 25) = " + maximum);
int minimum = min_value(15, 25);
print("min_value(15, 25) = " + minimum);
float avg = calculate_average(10, 20);
print("calculate_average(10, 20) = " + avg);
int squared = power_of_two(7);
print("power_of_two(7) = " + squared);
// Тестируем строковые функции
string greeting = create_greeting("Alice");
print(greeting);
string repeated = repeat_string("Fox", 3);
print("repeat_string('Fox', 3) = " + repeated);
string user_info = format_user_info("john_doe", 25);
print(user_info);
string full_name = get_full_name("John", "Doe");
print("get_full_name('John', 'Doe') = " + full_name);
print("Modules test completed!");
fox();
+24
View File
@@ -0,0 +1,24 @@
// Тест функции read_file
print("=== Тест функции read_file ===");
// Создаем тестовый файл
string test_content = "Hello from FoxLang!";
// Тестируем чтение существующего файла
string content = read_file("telegram_bot/token.txt");
if (content != "") {
print("✅ Чтение файла: УСПЕШНО");
print("Содержимое: " + content);
} else {
print("❌ Чтение файла: ОШИБКА");
}
// Тестируем чтение несуществующего файла
string empty = read_file("nonexistent.txt");
if (empty == "") {
print("✅ Обработка ошибки: УСПЕШНО");
} else {
print("❌ Обработка ошибки: ОШИБКА");
}
print("=== Тест завершен ===");
-24
View File
@@ -1,24 +0,0 @@
// Функция, которая проверяет число и возвращает код ошибки
int checkNumber(int n) {
if (n < 0) {
return 1; // Код ошибки 1: число отрицательное
}
if (n > 100) {
return 2; // Код ошибки 2: число слишком большое
}
return 0; // 0 - всё хорошо
}
// Переменная для теста
int val = -5;
// присваиваем результат функции в переменную!
int errorCode = checkNumber(val);
// Проверяем, что записалось
if (errorCode == 0) {
print("Success!");
} else {
print("Error happened. Code:");
print(errorCode); // Выведет 1
}
-29
View File
@@ -1,29 +0,0 @@
int coins = 100;
string playerName = "Alex";
// Коментприй
void showStats() {
print("--- Stats ---");
print("Player: " + playerName);
print("Coins: " + coins);
}
void mainLogic() {
print("Welcome to Fox Game!");
showStats();
print("You found a chest! Adding 50 coins.");
coins = coins + 50;
showStats();
print("Enter new name:");
playerName = input();
print("Updated profile:");
showStats();
}
void init() {
print("Initializing libs...");
}
+24
View File
@@ -0,0 +1,24 @@
// string_utils.fox - Строковые утилиты
string create_greeting(string name) {
return "Hello, " + name + "!";
}
string repeat_string(string text, int count) {
string result = "";
int i = 0;
while (i < count) {
result = result + text;
i = i + 1;
}
return result;
}
string format_user_info(string user_name, int age) {
return "User: " + user_name + ", Age: " + age;
}
// Функция с подчеркиванием
string get_full_name(string first_name, string last_name) {
return first_name + " " + last_name;
}
-30
View File
@@ -1,30 +0,0 @@
{
include("script.fox");
// Глоб. Переменные
string Player = "Artem";
int hpplayer = 100;
int level = 1;
int usr_input = 0;
void Hello() {
print("Привет, " + Player + "!");
print("Тебе предстоит пройти это подземелье");
}
Hello();
void ShowStats() {
print("-----------Статистика-----------");
print("Имя игрока: " + Player);
print("Здоровье: " + hpplayer);
print("Уровень: " + level);
}
ShowStats();
usr_input = input();
if (usr_input == 1) {
init();
} else {
print("Не найдено действие для этого ввода.");
}
}
+32
View File
@@ -0,0 +1,32 @@
// Тест базовых типов данных и переменных
print("=== Variables Test ===");
// Целые числа
int age = 25;
print("Age: " + age);
// Дробные числа
float pi = 3.14159;
print("Pi: " + pi);
// Строки
string name = "FoxLang";
print("Name: " + name);
// Логические значения
bool is_active = true;
bool is_disabled = false;
print("Active: " + is_active);
print("Disabled: " + is_disabled);
// Переменные с подчеркиваниями
string user_name = "john_doe";
int user_age = 30;
bool is_admin = false;
print("User: " + user_name);
print("User age: " + user_age);
print("Is admin: " + is_admin);
print("Variables test completed!");
fox();
Executable
+57
View File
@@ -0,0 +1,57 @@
#!/bin/bash
# Скрипт для запуска всех тестов FoxLang
echo "🦊 Running FoxLang Test Suite"
echo "=============================="
# Проверяем наличие интерпретатора
if [ ! -f "src/foxlang" ]; then
echo "❌ Error: foxlang interpreter not found. Please build it first:"
echo " cd src && g++ main.cpp Lexer.cpp Parser.cpp -o foxlang"
exit 1
fi
# Список тестов
tests=(
"variables.fox"
"functions.fox"
"arrays.fox"
"control_flow.fox"
"math_operations.fox"
"modules.fox"
"builtin_functions.fox"
)
passed=0
failed=0
# Запускаем каждый тест
for test in "${tests[@]}"; do
echo ""
echo "🧪 Running test: $test"
echo "----------------------------"
if ./src/foxlang "test/$test"; then
echo "$test - PASSED"
((passed++))
else
echo "$test - FAILED"
((failed++))
fi
done
echo ""
echo "=============================="
echo "📊 Test Results:"
echo " Passed: $passed"
echo " Failed: $failed"
echo " Total: $((passed + failed))"
if [ $failed -eq 0 ]; then
echo "🎉 All tests passed!"
exit 0
else
echo "💥 Some tests failed!"
exit 1
fi
+59
View File
@@ -0,0 +1,59 @@
// Полный тест новых возможностей FoxLang 4.0
using net;
// Новые типы данных
float temperature = 36.6;
bool isOnline = true;
bool hasError = false;
print("=== Тест новых типов ===");
print("Temperature: " + temperature);
print("Online status: " + isOnline);
print("Error status: " + hasError);
// Тест boolean логики
if (isOnline && !hasError) {
print("System is healthy");
}
if (temperature > 36.0) {
print("Temperature is normal");
}
// Тест сетевых функций
print("\n=== Тест сетевых функций ===");
string response = http_get("https://api.example.com/data");
print("HTTP GET: " + response);
string postResult = http_post("https://api.example.com/submit", "data=test");
print("HTTP POST: " + postResult);
// TCP тест
int tcpSocket = tcp_socket();
print("TCP Socket created: " + tcpSocket);
bool connected = tcp_connect(tcpSocket, "localhost", 8080);
if (connected) {
print("TCP connection established");
int bytesSent = tcp_send(tcpSocket, "Hello TCP Server!");
print("Bytes sent: " + bytesSent);
string received = tcp_receive(tcpSocket, 1024);
print("Received: " + received);
tcp_close(tcpSocket);
print("TCP connection closed");
}
// UDP тест
int udpSocket = udp_socket();
print("UDP Socket created: " + udpSocket);
int udpSent = udp_send(udpSocket, "localhost", 9090, "Hello UDP!");
print("UDP bytes sent: " + udpSent);
string udpData = udp_receive(udpSocket, 512);
print("UDP received: " + udpData);
print("\n=== Тест завершен ===");
fox();
+17
View File
@@ -0,0 +1,17 @@
// Тест логических операторов
using net;
bool isOnline = true;
bool hasError = false;
print("Online: " + isOnline);
print("Error: " + hasError);
if (isOnline && !hasError) {
print("System OK");
}
string response = http_get("test.com");
print("Response: " + response);
fox();
+40
View File
@@ -0,0 +1,40 @@
// Тест новых типов float и bool
using net.fox;
float pi = 3.14159;
bool isActive = true;
bool isComplete = false;
print("Pi value: " + pi);
print("Is active: " + isActive);
print("Is complete: " + isComplete);
// Тест сравнений
if (pi > 3.0) {
print("Pi is greater than 3");
}
if (isActive == true) {
print("System is active");
}
if (isComplete != true) {
print("Task is not complete");
}
// Тест сетевых функций
string response = http_get("https://example.com");
print("HTTP Response: " + response);
int socket = tcp_socket();
print("Socket created: " + socket);
bool connected = tcp_connect(socket, "localhost", 8080);
if (connected) {
print("Connected to server");
int sent = tcp_send(socket, "Hello Server");
print("Bytes sent: " + sent);
tcp_close(socket);
}
fox();
+4
View File
@@ -0,0 +1,4 @@
// Простой тест без using
string response = http_get("test");
print(response);
fox();
+7
View File
@@ -0,0 +1,7 @@
// Тест using библиотеки
using net.fox;
string response = http_get("https://example.com");
print("Response: " + response);
fox();
+10
View File
@@ -0,0 +1,10 @@
// Тест using без точки
using net;
string response = http_get("https://example.com");
print("Response: " + response);
int socket = tcp_socket();
print("Socket: " + socket);
fox();