From 895c678ca6ba2a60f069dc8b5b6d40f25b70f4cd Mon Sep 17 00:00:00 2001 From: SkrinVex Date: Thu, 22 Jan 2026 20:34:46 +0500 Subject: [PATCH] adeded new features --- .gitignore | 1 + DOCUMENTATION.md | 227 ++++++++++++++++++++++++++++++++++++++--------- src/AST.h | 203 ++++++++++++++++++++++++++++++++++++++++-- src/Lexer.cpp | 20 ++++- src/Parser.cpp | 137 +++++++++++++++++++++++++++- src/Token.h | 11 ++- 6 files changed, 544 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 06957d5..c904ab7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .kiro/settings/lsp.json web-ide +desktop-app diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index e5c133b..6d4fd06 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -117,11 +117,11 @@ int calculate_area(int width, int height) { --- -## 3. Математика и Логика +## 4. Математика и Логика Поддерживаются стандартные арифметические операции с учетом приоритета. -### Операторы +### Арифметические операторы | Оператор | Описание | Пример | | --- | --- | --- | @@ -132,18 +132,36 @@ int calculate_area(int width, int height) { | `%` | Остаток от деления | `10 % 3` (вернет 1) | | `++` | Инкремент (увеличение на 1) | `i++` (вернет старое значение, затем увеличит переменную) | -### Сравнение +### Операторы сравнения Операторы сравнения возвращают `1` (истина) или `0` (ложь). -* `==` (Равно) -* `!=` (Не равно) -* `<` (Меньше) -* `>` (Больше) +| Оператор | Описание | Пример | +| --- | --- | --- | +| `==` | Равно | `x == 5` | +| `!=` | Не равно | `x != 5` | +| `<` | Меньше | `x < 10` | +| `>` | Больше | `x > 0` | + +### Логические операторы + +FoxLang поддерживает логические операторы для работы с boolean значениями: + +| Оператор | Описание | Пример | +| --- | --- | --- | +| `&&` | Логическое И (AND) | `(x > 0) && (x < 10)` | +| `\|\|` | Логическое ИЛИ (OR) | `(x == 0) \|\| (x == 1)` | +| `!` | Логическое НЕ (NOT) | `!(x == 0)` | + +```cpp +bool is_valid = (age >= 18) && (age <= 65); +bool is_weekend = (day == "Saturday") || (day == "Sunday"); +bool is_not_empty = !name.empty(); +``` --- -## 4. Управляющие конструкции +## 5. Управляющие конструкции ### Условия (If / Else) @@ -178,6 +196,45 @@ for (int i = 0; i < 5; i++) { } ``` +### Switch/Case конструкции + +FoxLang поддерживает конструкции `switch/case` с поддержкой `break` и `default`: + +```cpp +int day = 3; +switch (day) { + case 1: + print("Понедельник"); + break; + case 2: + print("Вторник"); + break; + case 3: + print("Среда"); + break; + default: + print("Другой день"); + break; +} +``` + +### Управление циклами + +- `break` — Прерывает выполнение цикла или switch +- `continue` — Переходит к следующей итерации цикла + +```cpp +for (int i = 0; i < 10; i++) { + if (i == 5) { + continue; // Пропустить 5 + } + if (i == 8) { + break; // Выйти из цикла + } + print(i); +} +``` + ### Области видимости (Scope) Блоки кода `{ ... }` создают новую область видимости. Переменные, объявленные внутри блока, недоступны снаружи. @@ -194,31 +251,6 @@ int global = 10; --- -## 5. Функции - -Функции могут быть объявлены с типом возвращаемого значения или `void`. - -**Определение:** - -```cpp -void myFunc() { - print("Hello from function!"); -} - -int square(int x) { - return x * x; -} -``` - -**Вызов:** - -```cpp -myFunc(); -int result = square(5); -``` - ---- - ## 6. Массивы Массивы в FoxLang имеют фиксированный размер при создании. @@ -249,12 +281,123 @@ FoxLang поддерживает импорт внешних модулей. ## 8. Встроенные функции -| Функция | Описание | -| --- | --- | -| `print(expr)` | Выводит текст или результат выражения в консоль. | -| `input()` | Останавливает программу и ждет ввода строки от пользователя. | -| `round(expr)` | Округляет дробное число до ближайшего целого. | -| `random()` | Генерирует случайное число от 0 до 99. | -| `read_file(filename)` | Читает первую непустую строку из файла (игнорирует комментарии #). | -| `http_get(url)` | Выполняет HTTP GET запрос и возвращает ответ сервера. | -| `fox()` | Пасхалка: выводит название языка. | +### Ввод/Вывод +| Функция | Описание | Пример | +| --- | --- | --- | +| `print(expr...)` | Выводит текст или результат выражения в консоль. Может принимать несколько аргументов. | `print("Hello", name);` | +| `input()` | Ждет ввода строки от пользователя и возвращает её. | `string name = input();` | +| `input(prompt)` | Выводит приглашение и ждет ввода строки. | `string name = input("Имя: ");` | + +### Математические функции +| Функция | Описание | Пример | +| --- | --- | --- | +| `round(number)` | Округляет дробное число до ближайшего целого. | `int x = round(3.7); // 4` | +| `random(min, max)` | Генерирует случайное число в диапазоне от min до max включительно. | `int dice = random(1, 6);` | + +### Работа с файлами +| Функция | Описание | Пример | +| --- | --- | --- | +| `read_file(filename)` | Читает первую непустую строку из файла (игнорирует комментарии #). | `string config = read_file("config.txt");` | + +### HTTP запросы +| Функция | Описание | Пример | +| --- | --- | --- | +| `httpget(url)` | Выполняет HTTP GET запрос и возвращает ответ сервера. | `string data = httpget("https://api.example.com");` | +| `httppost(url, data)` | Выполняет HTTP POST запрос с данными. | `string response = httppost(url, "{\"key\":\"value\"}");` | +| `httppost(url, data, content_type)` | HTTP POST с указанием типа контента. | `httppost(url, data, "application/json");` | +| `httpput(url, data)` | Выполняет HTTP PUT запрос с данными. | `string response = httpput(url, data);` | +| `httpput(url, data, content_type)` | HTTP PUT с указанием типа контента. | `httpput(url, data, "text/plain");` | +| `httpdelete(url)` | Выполняет HTTP DELETE запрос. | `string response = httpdelete(url);` | + +### Работа со строками и JSON +| Функция | Описание | Пример | +| --- | --- | --- | +| `json_get(json_string, key)` | Извлекает значение по ключу из JSON строки. Поддерживает ключи: "chat_id", "text", "update_id". | `string chat_id = json_get(response, "chat_id");` | +| `str_contains(text, substring)` | Проверяет, содержит ли строка подстроку. Возвращает `true` или `false`. | `bool found = str_contains("Hello World", "World");` | +| `str_to_int(string)` | Преобразует строку в целое число. При ошибке возвращает 0. | `int num = str_to_int("123");` | + +### Ввод с клавиатуры (низкоуровневый) +| Функция | Описание | Пример | +| --- | --- | --- | +| `getch()` | Читает один символ с клавиатуры без нажатия Enter. | `string key = getch();` | +| `kbhit()` | Проверяет, была ли нажата клавиша. Возвращает `true` или `false`. | `bool pressed = kbhit();` | + +### Системные функции +| Функция | Описание | Пример | +| --- | --- | --- | +| `wait(milliseconds)` | Приостанавливает выполнение программы на указанное количество миллисекунд. | `wait(1000); // Пауза 1 секунда` | +| `fox()` | Пасхалка: выводит название языка "FoxLang". | `fox();` | + +--- + +## 9. Современный синтаксис + +FoxLang поддерживает современные соглашения по именованию и синтаксису: + +### Идентификаторы с подчеркиваниями + +В отличие от старых версий, FoxLang теперь полностью поддерживает идентификаторы с подчеркиваниями: + +```cpp +// Переменные +string user_name = "john_doe"; +int max_health = 100; +bool is_game_over = false; + +// Функции +void calculate_damage(int base_damage, float multiplier) { + // ... +} + +int get_player_score() { + return player_score; +} +``` + +### Глобальные переменные + +FoxLang поддерживает объявление глобальных переменных с ключевым словом `global`: + +```cpp +global int game_score = 0; +global string player_name = "Unknown"; + +void update_score(int points) { + game_score = game_score + points; +} + +void main() { + print("Score: " + game_score); + update_score(100); + print("New score: " + game_score); +} +``` + +### Примеры современного кода + +```cpp +// Современная функция с подчеркиваниями +bool check_user_permissions(string user_role, int required_level) { + if (user_role == "admin") { + return true; + } + + int user_level = get_user_level(user_role); + return user_level >= required_level; +} + +// Работа с массивами +void sort_user_scores(array scores, int count) { + for (int i = 0; i < count - 1; i++) { + for (int j = 0; j < count - i - 1; j++) { + if (get(scores, j) > get(scores, j + 1)) { + int temp = get(scores, j); + set(scores, j, get(scores, j + 1)); + set(scores, j + 1, temp); + } + } + } +} +``` + +--- diff --git a/src/AST.h b/src/AST.h index 79a2905..9801483 100644 --- a/src/AST.h +++ b/src/AST.h @@ -9,6 +9,15 @@ #include #include #include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif struct Node; @@ -74,6 +83,9 @@ struct ReturnValue { Value value; }; +struct BreakException {}; +struct ContinueException {}; + 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); @@ -116,14 +128,58 @@ struct FuncCallNode : Node { Value eval(Context& ctx) override { // Встроенные функции - if (name == "print" && args.size() == 1) { - std::cout << args[0]->eval(ctx).value << std::endl; + if (name == "print") { + if (args.empty()) { + std::cout << std::endl; + } else { + for (size_t i = 0; i < args.size(); i++) { + if (i > 0) std::cout << " "; + std::cout << args[i]->eval(ctx).value; + } + std::cout << std::endl; + } return {"void", ""}; } - if (name == "input" && args.size() == 0) { - std::string input; std::getline(std::cin, input); + if (name == "input") { + if (args.size() == 1) { + // Вывести приглашение + std::cout << args[0]->eval(ctx).value; + } + std::string input; + std::getline(std::cin, input); return {"string", input}; } + if (name == "getch" && args.size() == 0) { +#ifdef _WIN32 + return {"string", std::string(1, _getch())}; +#else + struct termios oldt, newt; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + char ch = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return {"string", std::string(1, ch)}; +#endif + } + if (name == "kbhit" && args.size() == 0) { +#ifdef _WIN32 + return {"bool", _kbhit() ? "true" : "false"}; +#else + int ch = getchar(); + if (ch != EOF) { + ungetc(ch, stdin); + return {"bool", "true"}; + } + return {"bool", "false"}; +#endif + } + if (name == "wait" && args.size() == 1) { + int milliseconds = std::stoi(args[0]->eval(ctx).value); + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); + return {"void", ""}; + } if (name == "round" && args.size() == 1) { double val = std::stod(args[0]->eval(ctx).value); return {"int", std::to_string((int)std::round(val))}; @@ -258,6 +314,68 @@ struct FuncCallNode : Node { return {"int", "0"}; } } + if (name == "httpget" && args.size() == 1) { + Value urlVal = args[0]->eval(ctx); + 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 == "httppost" && args.size() >= 2) { + Value urlVal = args[0]->eval(ctx); + Value dataVal = args[1]->eval(ctx); + std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json"; + + std::string cmd = "curl -s -X POST -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\""; + 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 == "httpput" && args.size() >= 2) { + Value urlVal = args[0]->eval(ctx); + Value dataVal = args[1]->eval(ctx); + std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json"; + + std::string cmd = "curl -s -X PUT -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\""; + 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 == "httpdelete" && args.size() == 1) { + Value urlVal = args[0]->eval(ctx); + std::string cmd = "curl -s -X DELETE \"" + 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}; + } // Пользовательские функции auto funcNodeBase = ctx.getFunc(name); @@ -494,7 +612,13 @@ struct WhileNode : Node { : condition(std::move(c)), body(std::move(b)) {} Value eval(Context& ctx) override { while (condition->eval(ctx).value == "true") { - body->eval(ctx); + try { + body->eval(ctx); + } catch (const BreakException&) { + break; + } catch (const ContinueException&) { + continue; + } } return {"void", ""}; } @@ -507,13 +631,80 @@ struct ForNode : Node { Value eval(Context& ctx) override { if (init) init->eval(ctx); while (condition->eval(ctx).value == "true") { - body->eval(ctx); + try { + body->eval(ctx); + } catch (const BreakException&) { + break; + } catch (const ContinueException&) { + // continue - выполняем step и продолжаем цикл + } if (step) step->eval(ctx); } return {"void", ""}; } }; +struct BreakNode : Node { + Value eval(Context& ctx) override { + throw BreakException{}; + } +}; + +struct ContinueNode : Node { + Value eval(Context& ctx) override { + throw ContinueException{}; + } +}; + +struct WaitNode : Node { + std::unique_ptr timeExpr; + WaitNode(std::unique_ptr t) : timeExpr(std::move(t)) {} + Value eval(Context& ctx) override { + int milliseconds = std::stoi(timeExpr->eval(ctx).value); + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); + return {"void", ""}; + } +}; + +struct SwitchNode : Node { + std::unique_ptr expr; + std::vector, std::unique_ptr>> cases; // value, body + std::unique_ptr defaultCase; + + SwitchNode(std::unique_ptr e) : expr(std::move(e)) {} + + Value eval(Context& ctx) override { + Value switchValue = expr->eval(ctx); + bool executed = false; + bool fallthrough = false; + + for (auto& caseItem : cases) { + if (!executed && !fallthrough) { + Value caseValue = caseItem.first->eval(ctx); + if (switchValue.value == caseValue.value) { + executed = true; + fallthrough = true; + } + } + + if (fallthrough) { + try { + caseItem.second->eval(ctx); + } catch (const BreakException&) { + fallthrough = false; + break; + } + } + } + + if (!executed && defaultCase) { + defaultCase->eval(ctx); + } + + return {"void", ""}; + } +}; + struct InputNode : Node { Value eval(Context& ctx) override { std::string input; std::getline(std::cin, input); diff --git a/src/Lexer.cpp b/src/Lexer.cpp index c68c0c4..f803dea 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -68,10 +68,10 @@ std::vector Lexer::tokenize() { else if (id == "round") tokens.push_back({TokenType::ROUND, id, line}); else if (id == "random") tokens.push_back({TokenType::RANDOM, id, line}); else if (id == "fox") tokens.push_back({TokenType::FOX, id, line}); - else if (id == "read_file") tokens.push_back({TokenType::READ_FILE, id, line}); - else if (id == "json_get") tokens.push_back({TokenType::JSON_GET, id, line}); - else if (id == "str_contains") tokens.push_back({TokenType::STR_CONTAINS, id, line}); - else if (id == "str_to_int") tokens.push_back({TokenType::STR_TO_INT, id, line}); + else if (id == "readfile") tokens.push_back({TokenType::READ_FILE, id, line}); + else if (id == "jsonget") tokens.push_back({TokenType::JSON_GET, id, line}); + else if (id == "strcontains") tokens.push_back({TokenType::STR_CONTAINS, id, line}); + else if (id == "strtoint") tokens.push_back({TokenType::STR_TO_INT, id, line}); else if (id == "int") tokens.push_back({TokenType::INT_KW, id, line}); else if (id == "float") tokens.push_back({TokenType::FLOAT_KW, id, line}); else if (id == "string") tokens.push_back({TokenType::STRING_KW, id, line}); @@ -83,6 +83,12 @@ std::vector Lexer::tokenize() { else if (id == "for") tokens.push_back({TokenType::FOR, id, line}); else if (id == "if") tokens.push_back({TokenType::IF, id, line}); else if (id == "else") tokens.push_back({TokenType::ELSE, id, line}); + else if (id == "switch") tokens.push_back({TokenType::SWITCH, id, line}); + else if (id == "case") tokens.push_back({TokenType::CASE, id, line}); + else if (id == "default") tokens.push_back({TokenType::DEFAULT, id, line}); + else if (id == "break") tokens.push_back({TokenType::BREAK, id, line}); + else if (id == "continue") tokens.push_back({TokenType::CONTINUE, id, line}); + else if (id == "wait") tokens.push_back({TokenType::WAIT, id, line}); else if (id == "array") tokens.push_back({TokenType::ARRAY, id, line}); else if (id == "set") tokens.push_back({TokenType::SET, id, line}); else if (id == "get") tokens.push_back({TokenType::GET, id, line}); @@ -91,6 +97,12 @@ std::vector Lexer::tokenize() { else if (id == "using") tokens.push_back({TokenType::USING, id, line}); else if (id == "return") tokens.push_back({TokenType::RETURN, id, line}); else if (id == "global") tokens.push_back({TokenType::GLOBAL, id, line}); + else if (id == "httpget") tokens.push_back({TokenType::HTTP_GET, id, line}); + else if (id == "httppost") tokens.push_back({TokenType::HTTP_POST, id, line}); + else if (id == "httpput") tokens.push_back({TokenType::HTTP_PUT, id, line}); + else if (id == "httpdelete") tokens.push_back({TokenType::HTTP_DELETE, id, line}); + else if (id == "getch") tokens.push_back({TokenType::GETCH, id, line}); + else if (id == "kbhit") tokens.push_back({TokenType::KBHIT, id, line}); else tokens.push_back({TokenType::IDENTIFIER, id, line}); } else { diff --git a/src/Parser.cpp b/src/Parser.cpp index 9060f0c..8581271 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -93,8 +93,13 @@ std::unique_ptr Parser::primary() { } if (tokens[pos].type == TokenType::INPUT) { - consume(TokenType::INPUT); consume(TokenType::LPAREN); consume(TokenType::RPAREN); - return std::make_unique(); + consume(TokenType::INPUT); consume(TokenType::LPAREN); + std::vector> args; + if (tokens[pos].type != TokenType::RPAREN) { + args.push_back(expression()); + } + consume(TokenType::RPAREN); + return std::make_unique("input", std::move(args)); } if (tokens[pos].type == TokenType::READ_FILE) { @@ -104,6 +109,70 @@ std::unique_ptr Parser::primary() { return std::make_unique(std::move(filename)); } + // HTTP функции в выражениях + if (tokens[pos].type == TokenType::HTTP_GET) { + consume(TokenType::HTTP_GET); consume(TokenType::LPAREN); + auto url = expression(); + consume(TokenType::RPAREN); + std::vector> args; + args.push_back(std::move(url)); + return std::make_unique("httpget", std::move(args)); + } + + if (tokens[pos].type == TokenType::HTTP_POST) { + consume(TokenType::HTTP_POST); consume(TokenType::LPAREN); + auto url = expression(); + consume(TokenType::COMMA); + auto data = expression(); + std::vector> args; + args.push_back(std::move(url)); + args.push_back(std::move(data)); + if (tokens[pos].type == TokenType::COMMA) { + consume(TokenType::COMMA); + args.push_back(expression()); + } + consume(TokenType::RPAREN); + return std::make_unique("httppost", std::move(args)); + } + + if (tokens[pos].type == TokenType::HTTP_PUT) { + consume(TokenType::HTTP_PUT); consume(TokenType::LPAREN); + auto url = expression(); + consume(TokenType::COMMA); + auto data = expression(); + std::vector> args; + args.push_back(std::move(url)); + args.push_back(std::move(data)); + if (tokens[pos].type == TokenType::COMMA) { + consume(TokenType::COMMA); + args.push_back(expression()); + } + consume(TokenType::RPAREN); + return std::make_unique("httpput", std::move(args)); + } + + if (tokens[pos].type == TokenType::HTTP_DELETE) { + consume(TokenType::HTTP_DELETE); consume(TokenType::LPAREN); + auto url = expression(); + consume(TokenType::RPAREN); + std::vector> args; + args.push_back(std::move(url)); + return std::make_unique("httpdelete", std::move(args)); + } + + // Функции ввода + if (tokens[pos].type == TokenType::GETCH) { + consume(TokenType::GETCH); consume(TokenType::LPAREN); consume(TokenType::RPAREN); + std::vector> args; + return std::make_unique("getch", std::move(args)); + } + + if (tokens[pos].type == TokenType::KBHIT) { + consume(TokenType::KBHIT); consume(TokenType::LPAREN); consume(TokenType::RPAREN); + std::vector> args; + return std::make_unique("kbhit", std::move(args)); + } + if (tokens[pos].type == TokenType::LPAREN) { consume(TokenType::LPAREN); auto n = expression(); @@ -343,6 +412,70 @@ std::unique_ptr Parser::statement() { return std::make_unique(std::move(cond), std::move(thenB), std::move(elseB)); } + if (tokens[pos].type == TokenType::BREAK) { + consume(TokenType::BREAK); consume(TokenType::SEMICOLON); + return std::make_unique(); + } + + if (tokens[pos].type == TokenType::CONTINUE) { + consume(TokenType::CONTINUE); consume(TokenType::SEMICOLON); + return std::make_unique(); + } + + if (tokens[pos].type == TokenType::WAIT) { + consume(TokenType::WAIT); consume(TokenType::LPAREN); + auto timeExpr = expression(); + consume(TokenType::RPAREN); consume(TokenType::SEMICOLON); + return std::make_unique(std::move(timeExpr)); + } + + if (tokens[pos].type == TokenType::SWITCH) { + consume(TokenType::SWITCH); consume(TokenType::LPAREN); + auto expr = expression(); + consume(TokenType::RPAREN); consume(TokenType::LBRACE); + + auto switchNode = std::make_unique(std::move(expr)); + + while (tokens[pos].type == TokenType::CASE || tokens[pos].type == TokenType::DEFAULT) { + if (tokens[pos].type == TokenType::CASE) { + consume(TokenType::CASE); + auto caseValue = expression(); + consume(TokenType::COLON); + + std::vector> caseStatements; + while (tokens[pos].type != TokenType::CASE && + tokens[pos].type != TokenType::DEFAULT && + tokens[pos].type != TokenType::RBRACE) { + caseStatements.push_back(statement()); + } + + auto caseBody = std::make_unique(); + for (auto& stmt : caseStatements) { + static_cast(caseBody.get())->stmts.push_back(std::move(stmt)); + } + + switchNode->cases.push_back(std::make_pair(std::move(caseValue), std::move(caseBody))); + } else if (tokens[pos].type == TokenType::DEFAULT) { + consume(TokenType::DEFAULT); consume(TokenType::COLON); + + std::vector> defaultStatements; + while (tokens[pos].type != TokenType::RBRACE) { + defaultStatements.push_back(statement()); + } + + auto defaultBody = std::make_unique(); + for (auto& stmt : defaultStatements) { + static_cast(defaultBody.get())->stmts.push_back(std::move(stmt)); + } + + switchNode->defaultCase = std::move(defaultBody); + } + } + + consume(TokenType::RBRACE); + return std::move(switchNode); + } + if (tokens[pos].type == TokenType::PRINT) { consume(TokenType::PRINT); consume(TokenType::LPAREN); auto expr = expression(); diff --git a/src/Token.h b/src/Token.h index 5a878b8..ebcbb66 100644 --- a/src/Token.h +++ b/src/Token.h @@ -12,13 +12,22 @@ enum class TokenType { PRINT, INPUT, ROUND, RANDOM, FOX, READ_FILE, JSON_GET, STR_CONTAINS, STR_TO_INT, INT_KW, FLOAT_KW, STRING_KW, BOOL_KW, VOID_KW, // Типы данных TRUE_KW, FALSE_KW, // Boolean литералы - WHILE, FOR, IF, ELSE, + WHILE, FOR, IF, ELSE, SWITCH, CASE, DEFAULT, ARRAY, SET, GET, SIZE, INCLUDE, USING, // Подключение файлов // НОВЫЕ: возврат и глобальные RETURN, GLOBAL, + // Управление потоком + BREAK, CONTINUE, WAIT, + + // Сетевые функции + HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE, + + // Ввод с клавиатуры + GETCH, KBHIT, + IDENTIFIER, END, ERROR };