Иправил баг с выполнением 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++.
Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры.
> **Главная фишка v4.0:** Умная система импорта, которая позволяет подключать библиотеки, выполняя только объявления функций и игнорируя исполняемый код.
## ✨ Ключевые возможности
- **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей.
+6 -6
View File
@@ -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<std::string>& 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<FuncDefNode*>(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<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::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++;
}
+33 -12
View File
@@ -14,9 +14,8 @@ Parser::Parser(std::vector<Token> 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<Node> Parser::primary() {
@@ -82,9 +81,8 @@ std::unique_ptr<Node> 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<Node> 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<Token> 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<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() {