Иправил баг с выполнением include

This commit is contained in:
SkrinVex
2025-12-28 00:59:33 +05:00
parent 16ebb96a2d
commit d1b4f5a6b5
4 changed files with 40 additions and 22 deletions
-2
View File
@@ -5,8 +5,6 @@
**FoxLang** — это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++. **FoxLang** — это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++.
Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры. Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры.
> **Главная фишка v4.0:** Умная система импорта, которая позволяет подключать библиотеки, выполняя только объявления функций и игнорируя исполняемый код.
## ✨ Ключевые возможности ## ✨ Ключевые возможности
- **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей. - **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей.
+6 -6
View File
@@ -33,24 +33,24 @@ struct Context {
std::string getVar(const std::string& name) { std::string 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);
std::cerr << "Runtime Error: Variable '" << name << "' not found." << std::endl; exit(1); throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!");
} }
std::vector<std::string>& getArray(const std::string& name) { std::vector<std::string>& 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);
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) { void setVar(const std::string& name, const std::string& val) {
if (variables.count(name)) { variables[name] = val; return; } if (variables.count(name)) { variables[name] = val; return; }
if (parent) { parent->setVar(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) { void defineVar(const std::string& name, const std::string& val) {
if (variables.count(name)) { 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; variables[name] = val;
} }
@@ -125,13 +125,13 @@ struct FuncCallNode : Node {
std::string eval(Context& ctx) override { std::string eval(Context& ctx) override {
auto funcNodeBase = ctx.getFunc(name); auto funcNodeBase = ctx.getFunc(name);
if (!funcNodeBase) { 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<FuncDefNode*>(funcNodeBase.get()); FuncDefNode* funcDef = static_cast<FuncDefNode*>(funcNodeBase.get());
if (args.size() != funcDef->params.size()) { 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<std::string> argValues; std::vector<std::string> argValues;
+1 -2
View File
@@ -87,8 +87,7 @@ std::vector<Token> Lexer::tokenize() {
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;
default: default:
std::cerr << "Lexer Error: Unknown char '" << current << "' at line " << line << std::endl; throw std::runtime_error(std::string("Runtime Error: Unknown character '") + current + "' at line " + std::to_string(line));
exit(1);
} }
pos++; pos++;
} }
+33 -12
View File
@@ -14,9 +14,8 @@ Parser::Parser(std::vector<Token> t) : tokens(t) {}
Token Parser::consume(TokenType type) { Token Parser::consume(TokenType type) {
if (tokens[pos].type == type) return tokens[pos++]; if (tokens[pos].type == type) return tokens[pos++];
std::cerr << "Syntax Error: Expected token " << (int)type throw std::runtime_error("Syntax Error: Expected token " + std::to_string((int)type) +
<< " got '" << tokens[pos].value << "' line " << tokens[pos].line << std::endl; " got '" + tokens[pos].value + "' line " + std::to_string(tokens[pos].line));
exit(1);
} }
std::unique_ptr<Node> Parser::primary() { std::unique_ptr<Node> Parser::primary() {
@@ -82,9 +81,8 @@ std::unique_ptr<Node> Parser::primary() {
return n; return n;
} }
std::cerr << "Parser Error: Unexpected token '" << tokens[pos].value throw std::runtime_error("Parser Error: Unexpected token '" + tokens[pos].value +
<< "' at line " << tokens[pos].line << std::endl; "' at line " + std::to_string(tokens[pos].line));
exit(1);
} }
std::unique_ptr<Node> Parser::multiplication() { std::unique_ptr<Node> Parser::multiplication() {
@@ -129,12 +127,35 @@ void processInclude(std::string filename, Context& ctx, std::string currentFile)
std::string dir = getDirectory(currentFile); std::string dir = getDirectory(currentFile);
std::string fullPath = dir + filename; std::string fullPath = dir + filename;
std::ifstream file(fullPath); 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()); Lexer lexer(buffer.str());
Parser parser(lexer.tokenize()); std::vector<Token> tokens = lexer.tokenize();
parser.globalContext = ctx; parser.currentFile = fullPath; parser.importMode = true;
parser.run(); ctx = parser.globalContext; 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<Node> Parser::statement() { std::unique_ptr<Node> Parser::statement() {
@@ -276,7 +297,7 @@ std::unique_ptr<Node> 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() { void Parser::run() {