Skip to content

Commit

Permalink
feat: Add validation of assignation
Browse files Browse the repository at this point in the history
Part of #25

- check name exists
- check it's not a constant
- check type equality
  • Loading branch information
Gashmob committed Sep 15, 2024
1 parent 9d52831 commit 91703c9
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 10 deletions.
5 changes: 4 additions & 1 deletion include/filc/validation/Name.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ class Name {
public:
Name();

Name(std::string name, std::shared_ptr<AbstractType> type);
Name(bool constant, std::string name, std::shared_ptr<AbstractType> type);

[[nodiscard]] auto isConstant() const -> bool;

[[nodiscard]] auto getName() const -> const std::string&;

[[nodiscard]] auto getType() const -> std::shared_ptr<AbstractType>;

private:
bool _constant;
std::string _name;
std::shared_ptr<AbstractType> _type;
};
Expand Down
7 changes: 5 additions & 2 deletions src/validation/Name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@

using namespace filc;

Name::Name() = default;
Name::Name() : _constant(true) {}

Name::Name(std::string name, std::shared_ptr<AbstractType> type) : _name(std::move(name)), _type(std::move(type)) {}
Name::Name(bool constant, std::string name, std::shared_ptr<AbstractType> type)
: _constant(constant), _name(std::move(name)), _type(std::move(type)) {}

auto Name::isConstant() const -> bool { return _constant; }

auto Name::getName() const -> const std::string & { return _name; }

Expand Down
37 changes: 34 additions & 3 deletions src/validation/ValidationVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* SOFTWARE.
*/
#include "filc/validation/ValidationVisitor.h"
#include "filc/grammar/assignation/Assignation.h"
#include "filc/grammar/identifier/Identifier.h"
#include "filc/grammar/literal/Literal.h"
#include "filc/grammar/program/Program.h"
Expand Down Expand Up @@ -126,6 +127,7 @@ auto ValidationVisitor::visitVariableDeclaration(VariableDeclaration *variable)
_context->stack();
_context->set("return", true);
variable->getValue()->accept(this);
_context->unstack();
const auto value_type = variable->getValue()->getType();
if (value_type == nullptr) {
throw std::logic_error("Variable value has no type");
Expand Down Expand Up @@ -154,12 +156,12 @@ auto ValidationVisitor::visitVariableDeclaration(VariableDeclaration *variable)
}

variable->setType(variable_type);
_environment->addName(Name(variable->getName(), variable_type));
_environment->addName(Name(variable->isConstant(), variable->getName(), variable_type));
}

auto ValidationVisitor::visitIdentifier(Identifier *identifier) -> void {
if (!_environment->hasName(identifier->getName())) {
_out << Message(ERROR, "Unknown name, don't what it refers to: " + identifier->getName(),
_out << Message(ERROR, "Unknown name, don't know what it refers to: " + identifier->getName(),
identifier->getPosition(), ERROR_COLOR);
return;
}
Expand All @@ -177,5 +179,34 @@ auto ValidationVisitor::visitBinaryCalcul(BinaryCalcul *calcul) -> void {
}

auto ValidationVisitor::visitAssignation(Assignation *assignation) -> void {
throw std::logic_error("Not implemented yet");
if (!_environment->hasName(assignation->getIdentifier())) {
_out << Message(ERROR, "Unknown name, don't know what it refers to: " + assignation->getIdentifier(),
assignation->getPosition(), ERROR_COLOR);
return;
}
const auto name = _environment->getName(assignation->getIdentifier());
if (name.isConstant()) {
_out << Message(ERROR, "Cannot modify a constant", assignation->getPosition(), ERROR_COLOR);
return;
}

_context->stack();
_context->set("return", true);
assignation->getValue()->accept(this);
_context->unstack();
const auto value_type = assignation->getValue()->getType();
if (value_type->getName() != name.getType()->getName()) {
const auto variable_type_dump = name.getType()->getDisplayName() != name.getType()->getName()
? name.getType()->getDisplayName() + " aka " + name.getType()->getName()
: name.getType()->getDisplayName();
const auto value_type_dump = value_type->getDisplayName() != value_type->getName()
? value_type->getDisplayName() + " aka " + value_type->getName()
: value_type->getDisplayName();
_out << Message(
ERROR, "Cannot assign value of type " + value_type_dump + " to a variable of type " + variable_type_dump,
assignation->getPosition(), ERROR_COLOR);
return;
}

assignation->setType(name.getType());
}
1 change: 1 addition & 0 deletions tests/unit/Fixtures/validation/assignation.fil
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
var id = 3
id = 478
5 changes: 3 additions & 2 deletions tests/unit/validation/EnvironmentTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ TEST(Environment, Name) {
filc::Environment env;
ASSERT_FALSE(env.hasName("my_name"));
ASSERT_THROW(env.getName("my_name"), std::logic_error);
env.addName(filc::Name("my_name", env.getType("i32")));
ASSERT_THROW(env.addName(filc::Name("my_name", env.getType("i64"))), std::logic_error);
env.addName(filc::Name(false, "my_name", env.getType("i32")));
ASSERT_THROW(env.addName(filc::Name(true, "my_name", env.getType("i64"))), std::logic_error);
ASSERT_TRUE(env.hasName("my_name"));
ASSERT_FALSE(env.getName("my_name").isConstant());
ASSERT_STREQ("my_name", env.getName("my_name").getName().c_str());
ASSERT_STREQ("i32", env.getName("my_name").getType()->getName().c_str());
}
4 changes: 3 additions & 1 deletion tests/unit/validation/NameTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@

TEST(Name, defaultConstructor) {
filc::Name name;
ASSERT_TRUE(name.isConstant());
ASSERT_STREQ("", name.getName().c_str());
ASSERT_EQ(nullptr, name.getType());
}

TEST(Name, constructor) {
filc::Name name("my_var", std::make_shared<filc::Type>("i32"));
filc::Name name(false, "my_var", std::make_shared<filc::Type>("i32"));
ASSERT_FALSE(name.isConstant());
ASSERT_STREQ("my_var", name.getName().c_str());
ASSERT_STREQ("i32", name.getType()->getName().c_str());
}
4 changes: 3 additions & 1 deletion tests/unit/validation/ValidationVisitorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,7 @@ TEST(ValidationVisitor, visitBinaryCalcul) {
TEST(ValidationVisitor, visitAssignation) {
VISITOR;
const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/assignation.fil");
ASSERT_THROW(program->accept(&visitor), std::logic_error);
program->accept(&visitor);
ASSERT_THAT(std::string(std::istreambuf_iterator<char>(ss), {}), IsEmpty());
ASSERT_STREQ("int", program->getExpressions()[1]->getType()->getDisplayName().c_str());
}

0 comments on commit 91703c9

Please sign in to comment.