Skip to content

Commit

Permalink
REPL Almost done (#76 from wesuRage/main)
Browse files Browse the repository at this point in the history
REPL Almost done
  • Loading branch information
wesuRage authored Jan 19, 2025
2 parents df009cb + 840d2c2 commit 59f495f
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 149 deletions.
1 change: 1 addition & 0 deletions include/frontend/parser/printer/print_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "frontend/parser/printer/nodes/statements/print_if.h"
#include "frontend/parser/printer/nodes/statements/print_extern.h"
#include "frontend/parser/printer/nodes/statements/print_enum.h"
#include "frontend/parser/printer/nodes/statements/print_while.h"

void print_ast_node(const AstNode *node, int depth, VisitedNodes *visited);
const char *returnASTNodeName(NodeType node_type);
Expand Down
280 changes: 132 additions & 148 deletions src/backend/generator/generator.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,201 +45,185 @@ extern "C" {
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
#include <llvm/Support/TargetSelect.h>

// Função para adicionar o código de entrada (entry.main) e executar
void createMainFunc(llvm::Module &module, llvm::LLVMContext &context, llvm::IRBuilder<llvm::NoFolder> &builder) {
llvm::FunctionType *mainFuncType = llvm::FunctionType::get(builder.getVoidTy(), false);
llvm::Function *mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "entry.main", module);

llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, "entry", mainFunc);
builder.SetInsertPoint(entryBlock);

FILE *outFile = fopen("repl.glx", "r");

int count = 0;
Token *tokenArray = tokenize(outFile, "repl.glx", &count); // Passando FILE*, nome do arquivo e count

// Gerar AST com base nos tokens
Parser parser = parser_new();
AstNode *ast = produce_ast(&parser, tokenArray, count, true); // Função fornecida por você
if (!ast) {
std::cerr << "Error: Invalid input or failed to parse AST.\n";
}

generate_ir(ast, context, module, builder);

// Adicionar código gerado ao JIT
builder.CreateRetVoid();
}

// Função para processar os nós AST
void processAstNode(AstNode *node, std::string &Line, FILE *outFile, std::stack<std::string> &declarationStack, std::vector<std::string>& codeLines) {
if (node == nullptr) {
std::cerr << "Error: Encountered null node!" << std::endl;
return;
}

// Verificação usando switch para os tipos de nós
switch (node->kind) {
case NODE_EXTERN:
case NODE_FUNCTION:
case NODE_VARIABLE:
case NODE_ASSIGNMENT:
// Se for uma função, variável ou atribuição, empilhar a linha
declarationStack.push(Line);
// Armazenar o código no vetor para mais tarde
codeLines.push_back(Line);
break;
default:
// Se não for declaração nem atribuição, processa normalmente
break;
}
}

// Função para concatenar as declarações e escrevê-las no arquivo
void writeDeclarationsToFile(std::stack<std::string> &declarationStack, FILE *outFile) {
std::vector<std::string> declarations; // Vetor para armazenar as declarações

// Empilhar as declarações no vetor
while (!declarationStack.empty()) {
declarations.push_back(declarationStack.top());
declarationStack.pop();
}

// Concatenar as declarações em uma única string
std::string allDeclarations;
for (const auto& decl : declarations) {
allDeclarations += decl + "\n"; // Adiciona um newline para separar as declarações
}

// Escrever a string concatenada no arquivo
fprintf(outFile, "%s", allDeclarations.c_str());
}

// Função principal do REPL
int startREPL() {
// Inicializar o LLVM e o JIT
// Inicializar LLVM
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();

std::unique_ptr<llvm::LLVMContext> Context = std::make_unique<llvm::LLVMContext>();
// Criar o JIT fora do loop
auto JIT = llvm::orc::LLJITBuilder().create();
if (!JIT) {
llvm::errs() << "Failed to initialize LLJIT: " << llvm::toString(JIT.takeError()) << "\n";
llvm::errs() << "Erro ao inicializar LLJIT: " << llvm::toString(JIT.takeError()) << "\n";
return 1;
}
llvm::LLVMContext TheContext;

std::cout << "(GalaxyJIT REPL v2.0.0) Enter code below ('exit' to quit):\n";

llvm::IRBuilder<llvm::NoFolder> Builder(*Context);
llvm::Module TheModule("REPLModule", *Context);
std::vector<std::string> modules {
"libs/std.ll"
};

std::string Line;
for (const auto &file : modules) {
llvm::SMDiagnostic Err;

std::stack<std::string> declarationStack; // Pilha para armazenar declarações e atribuições
std::vector<std::string> codeLines; // Vetor para armazenar o código gerado
// Carregar o módulo
auto Module = llvm::parseIRFile(file, Err, TheContext);
if (!Module) {
llvm::errs() << "Erro ao carregar o arquivo " << file << ": " << Err.getMessage() << "\n";
continue; // Pula para o próximo módulo
}

while (true) {
// Abrir arquivo para escrita das declarações
FILE *outFile = fopen("repl.glx", "a");
if (!outFile) {
std::cerr << "Error opening file to write.\n";
return 1;
// Adicionar o módulo ao JIT
if (auto Err = (*JIT)->addIRModule(llvm::orc::ThreadSafeModule(std::move(Module), std::make_unique<llvm::LLVMContext>()))) {
llvm::errs() << "Erro ao adicionar o módulo " << file << " ao JIT: " << llvm::toString(std::move(Err)) << "\n";
continue; // Pula para o próximo módulo
}
}

enter_scope();

std::cout << "(GalaxyJIT REPL v1.0.0) Enter code below ('exit' to quit):\n";

std::string Line;
std::vector<std::string> codeLines;

while (true) {
std::cout << ">>> ";
std::getline(std::cin, Line);
if (Line.empty()) continue;
if (Line == "exit") break;

// 1. Escrever as declarações no arquivo
writeDeclarationsToFile(declarationStack, outFile);

// 2. Adicionar a linha atual ao vetor de código
codeLines.push_back(Line);

// 3. Adicionar a linha ao arquivo imediatamente
// Criar um novo contexto, módulo e builder para cada iteração
auto TheModule = std::make_unique<llvm::Module>("GalaxyJIT", TheContext);
llvm::IRBuilder<llvm::NoFolder> Builder(TheContext);

std::ofstream stempFile("repl.glx", std::ios::out);
if (!stempFile) {
std::cerr << "Erro ao abrir arquivo temporário.\n";
return 1;
}

// Concatenar todas as linhas do código em uma única string, separadas por '\n'
std::string concatenatedCode = "";
for (const auto& code : codeLines) {
concatenatedCode += code + "\n";
// Escrever as linhas de código no arquivo temporário
for (const auto& line : codeLines) {
stempFile << line << "\n"; // Usando operador << para escrever a linha
}

fputs(concatenatedCode.c_str(), outFile);
stempFile.close();

// 4. Gerar AST a partir da entrada do código concatenado
FILE *tempFile = fopen("repl.glx", "r");
int count = 0;
Token *tokenArray = tokenize(outFile, "repl.glx", &count); // Passando FILE*, nome do arquivo e count
Token *tokens = tokenize(tempFile, "repl.glx", &count);
fclose(tempFile);

// Gerar AST com base nos tokens
Parser parser = parser_new();
AstNode *ast = produce_ast(&parser, tokenArray, count, true); // Função fornecida por você
AstNode *ast = produce_ast(&parser, tokens, count, true);
if (!ast) {
std::cerr << "Error: Invalid input or failed to parse AST.\n";
std::cerr << "Erro: Entrada inválida ou falha ao analisar AST.\n";
freeTokens(tokens, count);
continue;
}

if (ast->kind == NODE_PROGRAM) {
ProgramNode* programNode = (ProgramNode*)ast->data;

if (programNode->statement_count == 0) {
continue;
}

// 5. Processar os statements da AST
for (size_t i = 0; i < programNode->statement_count; ++i) {
processAstNode(programNode->statements[i], Line, outFile, declarationStack, codeLines);
}

// 6. criar a função main
createMainFunc(TheModule, *Context, Builder);

// Adicionar módulos externos ao JIT (libs)
std::vector<std::string> modules { "libs/std.ll" };
for (const auto &file : modules) {
llvm::SMDiagnostic Err;

// Carregar o módulo
auto Module = llvm::parseIRFile(file, Err, *Context);
if (!Module) {
llvm::errs() << "Erro ao carregar o arquivo " << file << ": " << Err.getMessage() << "\n";
continue; // Pula para o próximo módulo
// Criar a função entry.main
llvm::FunctionType *mainFuncType = llvm::FunctionType::get(Builder.getVoidTy(), false);
llvm::Function *mainFunc = llvm::Function::Create(mainFuncType, llvm::GlobalValue::WeakODRLinkage, "entry.main", *TheModule);

llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(TheContext, "entry", mainFunc);
Builder.SetInsertPoint(entryBlock);

generate_ir(ast, TheContext, *TheModule, Builder);

Builder.CreateRetVoid();

ProgramNode *programNode = (ProgramNode *)ast->data;

for (int i = 0; i < programNode->statement_count; i++) {
// Acessando diretamente a string em codeLines[i]
auto& currentCodeLine = codeLines[i];

// Verifica se o statement está dentro dos casos desejados
switch (programNode->statements[i]->kind) {
case NODE_EXTERN:
case NODE_FUNCTION:
case NODE_VARIABLE:
case NODE_ASSIGNMENT: {
// Verifica se 'currentCodeLine' é igual a 'Line' e, em caso afirmativo, move para o final
if (currentCodeLine == Line) {
// Remove a linha de onde está (atualmente 'i')
codeLines.erase(codeLines.begin() + i);
// Adiciona a linha no final do vetor
codeLines.push_back(Line);
continue; // Encontramos e movemos a linha, não precisamos continuar
}
}

// Adicionar o módulo ao JIT
if (auto Err = (*JIT)->addIRModule(llvm::orc::ThreadSafeModule(std::move(Module), std::make_unique<llvm::LLVMContext>()))) {
llvm::errs() << "Erro ao adicionar o módulo " << file << " ao JIT: " << llvm::toString(std::move(Err)) << "\n";
continue; // Pula para o próximo módulo
break; // Termina o case

case NODE_CALL:
case NODE_WHILE:
case NODE_FOR: {
// Para os outros tipos de statement, apenas remove a linha
if (currentCodeLine == Line) {
// Remove a linha de onde está (atualmente 'i')
codeLines.erase(codeLines.begin() + i);
// Adiciona a linha no final do vetor
continue; // Encontramos e movemos a linha, não precisamos continuar
}
}
break; // Termina o case
}
}

llvm::orc::ThreadSafeModule safeModule(std::make_unique<llvm::Module>("REPLModule", *Context), std::make_unique<llvm::LLVMContext>());
(*JIT)->addIRModule(std::move(safeModule));
// Verificar o módulo
std::string errorMsg;
llvm::raw_string_ostream errorStream(errorMsg);
if (llvm::verifyModule(*TheModule, &errorStream)) {
llvm::errs() << "Erro ao verificar módulo:\n" << errorStream.str() << "\n";
free_ast_node(ast);
freeTokens(tokens, count);
continue;
}

// 7. Executar a função 'entry.main' após adicionar o módulo
auto entryMainSymbol = (*JIT)->lookup("entry.main");
if (entryMainSymbol) {
auto *entryMainFunc = (void (*)())entryMainSymbol->getValue();
entryMainFunc(); // Executa a função 'entry.main'
} else {
std::cerr << "Error: entry.main not found.\n";
}
// Emitir o módulo em formato texto para o arquivo "repl.ll"
std::error_code EC;
llvm::raw_fd_ostream outFile("repl.ll", EC, llvm::sys::fs::OF_Text);
if (EC) {
llvm::errs() << "Erro ao abrir arquivo de saída para escrita: " << EC.message() << "\n";
free_ast_node(ast);
freeTokens(tokens, count);
continue;
}

// Limpeza da AST e tokens após o processamento
free_ast_node(ast);
freeTokens(tokenArray, count);
// Escrever o módulo no arquivo
TheModule->print(outFile, nullptr);

std::cout << "Processed input and updated stacks.\n";
// Adicionar o módulo ao JIT (sem usar o ResourceTracker diretamente)
if (auto Err = (*JIT)->addIRModule(llvm::orc::ThreadSafeModule(std::move(TheModule), std::make_unique<llvm::LLVMContext>()))) {
llvm::errs() << "Erro ao adicionar o módulo IR ao JIT: " << llvm::toString(std::move(Err)) << "\n";
free_ast_node(ast);
freeTokens(tokens, count);
return 1;
}

// Executar a função entry.main
auto Func = (*JIT)->lookup("entry.main");
if (!Func) {
llvm::errs() << "Erro: entry.main não encontrado.\n";
free_ast_node(ast);
freeTokens(tokens, count);
continue;
}

fclose(outFile); // Fechar o arquivo após a execução do REPL
auto EntryMain = (void (*)())(Func->getValue());
EntryMain();

free_ast_node(ast);
freeTokens(tokens, count);
}

return 0;
}


int main(int argc, char **argv) {
if (argc > 1 && std::string(argv[1]) == "--repl") {
startREPL();
Expand Down
1 change: 0 additions & 1 deletion src/frontend/parser/statements/parse_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ AstNode *parse_stmt(Parser *parser) {
case TOKEN_PACKAGE: return parse_package_stmt(parser);
case TOKEN_IMPORT: return parse_import_stmt(parser);
case TOKEN_FOR: return parse_for_stmt(parser);
case TOKEN_WHILE: return parse_while_stmt(parser);
case TOKEN_IF: return parse_if_stmt(parser);
case TOKEN_DEF: return parse_function_declaration_stmt(parser);
case TOKEN_AT: return parse_decorator_stmt(parser);
Expand Down

0 comments on commit 59f495f

Please sign in to comment.