Иправил баг с выполнением include
This commit is contained in:
@@ -5,8 +5,6 @@
|
|||||||
**FoxLang** — это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++.
|
**FoxLang** — это интерпретируемый язык программирования общего назначения, разработанный с нуля на C++.
|
||||||
Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры.
|
Он сочетает строгий синтаксис (в стиле C++/Java) с динамической гибкостью скриптовых языков. Проект демонстрирует реализацию собственного лексера, рекурсивного парсера, AST-дерева и модульной архитектуры.
|
||||||
|
|
||||||
> **Главная фишка v4.0:** Умная система импорта, которая позволяет подключать библиотеки, выполняя только объявления функций и игнорируя исполняемый код.
|
|
||||||
|
|
||||||
## ✨ Ключевые возможности
|
## ✨ Ключевые возможности
|
||||||
|
|
||||||
- **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей.
|
- **📁 Модульность:** Подключение файлов через `include("lib.fox")` с поддержкой относительных путей.
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user