Skip to content

Commit

Permalink
Fix Scopes (#38)
Browse files Browse the repository at this point in the history
* fix scopes and add extra type error check

* add tests

* add one more test

* add another scope test
  • Loading branch information
jackparsonss committed Jun 28, 2024
1 parent 8595de6 commit 9f0d561
Show file tree
Hide file tree
Showing 41 changed files with 231 additions and 150 deletions.
8 changes: 6 additions & 2 deletions include/ast/passes/define.h → include/ast/passes/def_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
#include "ast/symbol/symbol.h"
#include "ast/symbol/symbol_table.h"

class Define : public Pass {
class DefRef : public Pass {
private:
shared_ptr<SymbolTable> symbol_table;
bool is_builtin(std::string name);

public:
explicit Define(shared_ptr<SymbolTable> symbol_table);
explicit DefRef(shared_ptr<SymbolTable> symbol_table);
void visit_block(shared_ptr<ast::Block>) override;
void visit_declaration(shared_ptr<ast::Declaration>) override;
void visit_parameter(shared_ptr<ast::Parameter>) override;
void visit_function(shared_ptr<ast::Function>) override;
void visit_variable(shared_ptr<ast::Variable>) override;
void visit_call(shared_ptr<ast::Call>) override;
};
17 changes: 0 additions & 17 deletions include/ast/passes/reference.h

This file was deleted.

3 changes: 1 addition & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ set(
"${CMAKE_CURRENT_SOURCE_DIR}/ast/symbol/function_symbol.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/pass.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/define.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/reference.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/def_ref.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/type_check.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ast/passes/builtin.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/shared/type.cpp"
Expand Down
23 changes: 13 additions & 10 deletions src/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,15 @@ void ast::Function::xml(int level) {
<< type->get_name() << "\" name=\"" << name << "\" ref_name=\""
<< ref_name << "\">\n";

std::cout << std::string((level + 1) * 4, ' ') << "<parameters>\n";
for (const auto& param : params) {
param->xml(level + 2);
if (params.size() > 0) {
std::cout << std::string((level + 1) * 4, ' ') << "<parameters>\n";
for (const auto& param : params) {
param->xml(level + 2);
}
std::cout << std::string((level + 1) * 4, ' ') << "</parameters>\n";
}
std::cout << std::string((level + 1) * 4, ' ') << "</parameters>\n";
body->xml(level + 1);

body->xml(level + 1);
std::cout << std::string(level * 4, ' ') << "</function>\n";
}

Expand Down Expand Up @@ -294,16 +296,17 @@ std::string ast::Call::get_name() {
}

void ast::Call::xml(int level) {
std::cout << std::string(level * 4, ' ') << "<call name=\"" << this->name
<< "\" ref_name=\"" << this->function->get_ref_name()
<< "\" type=\"" << this->type->get_name() << "\">\n";
std::string ref = function ? function->get_ref_name() : "(unset)";
std::cout << std::string(level * 4, ' ') << "<call name=\"" << name
<< "\" ref_name=\"" << ref << "\" type=\"" << type->get_name()
<< "\">\n";

if (arguments.size() > 0) {
std::cout << std::string((level + 1) * 4, ' ') << "<args>\n";
std::cout << std::string((level + 1) * 4, ' ') << "<arguments>\n";
for (auto const& a : arguments) {
a->xml(level + 2);
}
std::cout << std::string((level + 1) * 4, ' ') << "</args>\n";
std::cout << std::string((level + 1) * 4, ' ') << "</arguments>\n";
}

std::cout << std::string(level * 4, ' ') << "</call>\n";
Expand Down
13 changes: 8 additions & 5 deletions src/ast/builder.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <any>
#include <stdexcept>
#include <vector>

Expand All @@ -6,8 +7,10 @@
#include "ast/builder.h"
#include "shared/context.h"

using std::any_cast;

#define cast_node(a, b) \
(dynamic_pointer_cast<a>(std::any_cast<shared_ptr<ast::Node>>(b)))
(dynamic_pointer_cast<a>(any_cast<shared_ptr<ast::Node>>(b)))
#define to_node(a) static_cast<shared_ptr<ast::Node>>(a)

Builder::Builder(shared_ptr<SymbolTable> symbol_table) {
Expand Down Expand Up @@ -147,7 +150,7 @@ std::any Builder::visitIdentifier(FusionParser::IdentifierContext* ctx) {

std::any Builder::visitBlock(FusionParser::BlockContext* ctx) {
Token* token = ctx->L_CURLY()->getSymbol();
auto block = std::make_shared<ast::Block>(token);
auto block = make_shared<ast::Block>(token);

for (auto const& s : ctx->statement()) {
shared_ptr<ast::Node> node = cast_node(ast::Node, visit(s));
Expand All @@ -163,16 +166,16 @@ std::any Builder::visitVariable(FusionParser::VariableContext* ctx) {
std::string name = ctx->ID()->getText();

ast::Qualifier qualifier =
std::any_cast<ast::Qualifier>(visit(ctx->qualifier()));
TypePtr type = std::any_cast<TypePtr>(visit(ctx->type()));
any_cast<ast::Qualifier>(visit(ctx->qualifier()));
TypePtr type = any_cast<TypePtr>(visit(ctx->type()));

auto var = make_shared<ast::Variable>(qualifier, type, name, token);
return to_node(var);
}

std::any Builder::visitFunction(FusionParser::FunctionContext* ctx) {
Token* token = ctx->FUNCTION()->getSymbol();
TypePtr type = std::any_cast<TypePtr>(visit(ctx->type()));
TypePtr type = any_cast<TypePtr>(visit(ctx->type()));
std::string name = ctx->ID()->getText();
auto block = cast_node(ast::Block, visit(ctx->block()));

Expand Down
116 changes: 116 additions & 0 deletions src/ast/passes/def_ref.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "ast/passes/def_ref.h"
#include "ast/ast.h"
#include "ast/symbol/function_symbol.h"
#include "errors.h"

DefRef::DefRef(shared_ptr<SymbolTable> symbol_table) : Pass("DefRef") {
this->symbol_table = symbol_table;
}

void DefRef::visit_block(shared_ptr<ast::Block> node) {
symbol_table->push();
for (const auto& node : node->nodes) {
visit(node);
}
symbol_table->pop();
}

void DefRef::visit_declaration(shared_ptr<ast::Declaration> node) {
if (symbol_table->resolve_local(node->var->get_name()).has_value()) {
throw SymbolError(
node->token->getLine(),
"variable " + node->var->get_name() + " already defined");
}

shared_ptr<ast::Variable> var = node->var;
shared_ptr<VariableSymbol> sym = make_shared<VariableSymbol>(var);

symbol_table->define(sym);

visit(node->expr);
}

void DefRef::visit_parameter(shared_ptr<ast::Parameter> node) {
shared_ptr<ast::Variable> var = node->var;
if (symbol_table->resolve_local(var->get_name()).has_value()) {
throw SymbolError(
node->token->getLine(),
"parameter " + node->var->get_name() + " already defined");
}

shared_ptr<VariableSymbol> sym = make_shared<VariableSymbol>(var);
symbol_table->define(sym);
}

void DefRef::visit_function(shared_ptr<ast::Function> node) {
if (symbol_table->resolve_bottom(name).has_value()) {
throw SymbolError(node->token->getLine(),
"function " + node->get_name() + " already defined");
}

shared_ptr<FunctionSymbol> sym =
std::make_shared<FunctionSymbol>(node, symbol_table->current_scope);
symbol_table->define(sym);

symbol_table->push();
for (const auto& param : node->params) {
visit(param);
}

symbol_table->push();
visit(node->body);
symbol_table->pop();
symbol_table->pop();
}

void DefRef::visit_variable(shared_ptr<ast::Variable> node) {
std::optional<SymbolPtr> var = symbol_table->resolve(node->get_name());
size_t line = node->token->getLine();
if (!var.has_value()) {
throw SymbolError(line,
"use of undefined variable: " + node->get_name());
}

shared_ptr<VariableSymbol> vs =
dynamic_pointer_cast<VariableSymbol>(var.value());
if (vs == nullptr) {
throw SymbolError(line, node->get_name() + " is not a variable");
}

node->set_type(vs->variable->get_type());
node->set_qualifier(vs->variable->get_qualifier());
node->set_ref_name(vs->variable->get_ref_name());
}

void DefRef::visit_call(shared_ptr<ast::Call> node) {
for (const auto& arg : node->arguments) {
visit(arg);
}

std::string name = node->get_name();
if (is_builtin(name) && node->arguments.size() > 0) {
name += "_" + node->arguments[0]->get_type()->get_name();
}

std::optional<SymbolPtr> var = symbol_table->resolve(name);
size_t line = node->token->getLine();
if (!var.has_value()) {
throw SymbolError(line, "called undefined function: " + name);
}

shared_ptr<FunctionSymbol> vs =
dynamic_pointer_cast<FunctionSymbol>(var.value());
if (vs == nullptr) {
throw SymbolError(line, node->get_name() + " is not a function");
}

node->set_function(vs->function);
}

bool DefRef::is_builtin(std::string name) {
if (name == "print" || name == "println") {
return true;
}

return false;
}
48 changes: 0 additions & 48 deletions src/ast/passes/define.cpp

This file was deleted.

6 changes: 2 additions & 4 deletions src/ast/passes/pass.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include "ast/passes/pass.h"
#include "ast/ast.h"
#include "ast/passes/builtin.h"
#include "ast/passes/define.h"
#include "ast/passes/reference.h"
#include "ast/passes/def_ref.h"
#include "ast/passes/type_check.h"

constexpr bool debug = false;
Expand All @@ -14,8 +13,7 @@ constexpr bool debug = false;
void Pass::run_passes(std::shared_ptr<ast::Block> ast,
shared_ptr<SymbolTable> symtab) {
std::vector<std::shared_ptr<Pass>> passes = {
std::make_shared<Define>(symtab),
std::make_shared<Reference>(symtab),
std::make_shared<DefRef>(symtab),
std::make_shared<TypeCheck>(),
std::make_shared<Builtin>(symtab),
};
Expand Down
55 changes: 0 additions & 55 deletions src/ast/passes/reference.cpp

This file was deleted.

Loading

0 comments on commit 9f0d561

Please sign in to comment.