From d1b4f5a6b5f7da2fe8614e0c7bad5a0806a85a5e Mon Sep 17 00:00:00 2001 From: SkrinVex Date: Sun, 28 Dec 2025 00:59:33 +0500 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B1=D0=B0=D0=B3=20=D1=81=20=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20include?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 -- src/AST.h | 12 ++++++------ src/Lexer.cpp | 3 +-- src/Parser.cpp | 45 +++++++++++++++++++++++++++++++++------------ 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4857fc2..c984634 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ **FoxLang** — это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++. Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры. -> **Главная фишка v4.0:** Умная система импорта, которая позволяет подключать библиотеки, выполняя только объявления функций и игнорируя исполняемый код. - ## ✨ Ключевые возможности - **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей. diff --git a/src/AST.h b/src/AST.h index 7963d19..85e79b7 100644 --- a/src/AST.h +++ b/src/AST.h @@ -33,24 +33,24 @@ struct Context { std::string getVar(const std::string& name) { if (variables.count(name)) return variables[name]; if (parent) return parent->getVar(name); - std::cerr << "Runtime Error: Variable '" << name << "' not found." << std::endl; exit(1); + throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!"); } std::vector& getArray(const std::string& name) { if (arrays.count(name)) return arrays[name]; if (parent) return parent->getArray(name); - std::cerr << "Runtime Error: Array '" << name << "' not found." << std::endl; exit(1); + throw std::runtime_error("Runtime Error: Array '" + name + "' not found!"); } void setVar(const std::string& name, const std::string& val) { if (variables.count(name)) { variables[name] = val; return; } if (parent) { parent->setVar(name, val); return; } - std::cerr << "Runtime Error: Variable '" << name << "' not defined." << std::endl; exit(1); + throw std::runtime_error("Error: Variable '" + name + "' not defined!"); } void defineVar(const std::string& name, const std::string& val) { if (variables.count(name)) { - std::cerr << "Runtime Error: Variable '" << name << "' already defined." << std::endl; exit(1); + throw std::runtime_error("Error: Variable '" + name + "' already defined!"); } variables[name] = val; } @@ -125,13 +125,13 @@ struct FuncCallNode : Node { std::string eval(Context& ctx) override { auto funcNodeBase = ctx.getFunc(name); if (!funcNodeBase) { - std::cerr << "Runtime Error: Function '" << name << "' not found." << std::endl; exit(1); + throw std::runtime_error("Runtime Error: Function '" + name + "' not found!"); } FuncDefNode* funcDef = static_cast(funcNodeBase.get()); if (args.size() != funcDef->params.size()) { - std::cerr << "Args count mismatch for '" << name << "'" << std::endl; exit(1); + throw std::runtime_error("Args count mismatch for '" + name + "'"); } std::vector argValues; diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 0abe40e..3056df0 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -87,8 +87,7 @@ std::vector Lexer::tokenize() { case '<': tokens.push_back({TokenType::LT, "<", line}); break; case '>': tokens.push_back({TokenType::GT, ">", line}); break; default: - std::cerr << "Lexer Error: Unknown char '" << current << "' at line " << line << std::endl; - exit(1); + throw std::runtime_error(std::string("Runtime Error: Unknown character '") + current + "' at line " + std::to_string(line)); } pos++; } diff --git a/src/Parser.cpp b/src/Parser.cpp index cc4147c..916515a 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -14,9 +14,8 @@ Parser::Parser(std::vector t) : tokens(t) {} Token Parser::consume(TokenType type) { if (tokens[pos].type == type) return tokens[pos++]; - std::cerr << "Syntax Error: Expected token " << (int)type - << " got '" << tokens[pos].value << "' line " << tokens[pos].line << std::endl; - exit(1); + throw std::runtime_error("Syntax Error: Expected token " + std::to_string((int)type) + + " got '" + tokens[pos].value + "' line " + std::to_string(tokens[pos].line)); } std::unique_ptr Parser::primary() { @@ -82,9 +81,8 @@ std::unique_ptr Parser::primary() { return n; } - std::cerr << "Parser Error: Unexpected token '" << tokens[pos].value - << "' at line " << tokens[pos].line << std::endl; - exit(1); + throw std::runtime_error("Parser Error: Unexpected token '" + tokens[pos].value + + "' at line " + std::to_string(tokens[pos].line)); } std::unique_ptr Parser::multiplication() { @@ -129,12 +127,35 @@ void processInclude(std::string filename, Context& ctx, std::string currentFile) std::string dir = getDirectory(currentFile); std::string fullPath = dir + filename; std::ifstream file(fullPath); - if (!file.is_open()) { file.open(filename); if(!file.is_open()) exit(1); } - std::stringstream buffer; buffer << file.rdbuf(); + + // Если не нашли по полному пути, ищем рядом с исполняемым файлом + if (!file.is_open()) { + file.open(filename); + if(!file.is_open()) { + throw std::runtime_error("Include Error: File '" + filename + "' not found."); + } + } + + std::stringstream buffer; + buffer << file.rdbuf(); + Lexer lexer(buffer.str()); - Parser parser(lexer.tokenize()); - parser.globalContext = ctx; parser.currentFile = fullPath; parser.importMode = true; - parser.run(); ctx = parser.globalContext; + std::vector tokens = lexer.tokenize(); + + Parser parser(tokens); + + // 1. Копируем текущую память внутрь include, чтобы он видел глобальные переменные + parser.globalContext = ctx; + parser.currentFile = fullPath; + + // ВАЖНО: Мы убрали parser.importMode = true; + // Теперь код внутри lib.fox (например, print) БУДЕТ выполняться. + parser.importMode = false; + + parser.run(); + + // 2. Возвращаем память обратно (функции из lib.fox появятся в main) + ctx = parser.globalContext; } std::unique_ptr Parser::statement() { @@ -276,7 +297,7 @@ std::unique_ptr Parser::statement() { } } - std::cerr << "Unknown statement " << tokens[pos].value << std::endl; exit(1); + throw std::runtime_error("Unknown statement " + tokens[pos].value); } void Parser::run() {