diff --git a/include/filc/grammar/Type.h b/include/filc/grammar/Type.h new file mode 100644 index 0000000..9c57fbe --- /dev/null +++ b/include/filc/grammar/Type.h @@ -0,0 +1,82 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef FILC_TYPE_H +#define FILC_TYPE_H + +#include +#include + +namespace filc { +class AbstractType { + public: + [[nodiscard]] virtual auto getName() const noexcept -> std::string = 0; + + [[nodiscard]] virtual auto getDisplayName() const noexcept -> std::string = 0; + + protected: + AbstractType() = default; +}; + +class Type final: public AbstractType { + public: + explicit Type(std::string name); + + [[nodiscard]] auto getName() const noexcept -> std::string override; + + [[nodiscard]] auto getDisplayName() const noexcept -> std::string override; + + private: + std::string _name; +}; + +class PointerType final: public AbstractType { + public: + explicit PointerType(std::shared_ptr pointed_type); + + [[nodiscard]] auto getName() const noexcept -> std::string override; + + [[nodiscard]] auto getDisplayName() const noexcept -> std::string override; + + private: + std::shared_ptr _pointed_type; +}; + +class AliasType final: public AbstractType { + public: + AliasType(std::string name, std::shared_ptr aliased_type); + + [[nodiscard]] auto getName() const noexcept -> std::string override; + + [[nodiscard]] auto getDisplayName() const noexcept -> std::string override; + + private: + std::string _name; + std::shared_ptr _aliased_type; +}; +} + +auto operator==(const std::shared_ptr &a, const std::shared_ptr &b) -> bool; +auto operator!=(const std::shared_ptr &a, const std::shared_ptr &b) -> bool; + +#endif // FILC_TYPE_H diff --git a/include/filc/grammar/expression/Expression.h b/include/filc/grammar/expression/Expression.h index 10cf025..2827a6f 100644 --- a/include/filc/grammar/expression/Expression.h +++ b/include/filc/grammar/expression/Expression.h @@ -27,6 +27,7 @@ #include "filc/grammar/ast.h" #include "filc/grammar/Visitor.h" #include "filc/grammar/Position.h" +#include "filc/grammar/Type.h" #include namespace filc { @@ -38,11 +39,16 @@ class Expression: public Visitable { [[nodiscard]] auto getPosition() const -> const Position&; + auto setType(const std::shared_ptr &type) -> void; + + [[nodiscard]] auto getType() const -> const std::shared_ptr&; + protected: Expression(); private: Position _position; + std::shared_ptr _type; }; } diff --git a/include/filc/utils/Message.h b/include/filc/utils/Message.h index 6431b5c..a333c84 100644 --- a/include/filc/utils/Message.h +++ b/include/filc/utils/Message.h @@ -29,6 +29,8 @@ #define WARNING "WARNING" #define WARNING_COLOR "\033[33m" +#define ERROR "ERROR" +#define ERROR_COLOR "\033[31m" namespace filc { class Message final { diff --git a/include/filc/validation/Environment.h b/include/filc/validation/Environment.h new file mode 100644 index 0000000..f55a57c --- /dev/null +++ b/include/filc/validation/Environment.h @@ -0,0 +1,47 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef FILC_ENVIRONMENT_H +#define FILC_ENVIRONMENT_H + +#include "filc/grammar/Type.h" +#include +#include + +namespace filc { +class Environment { + public: + Environment(); + + [[nodiscard]] auto hasType(const std::string &name) const -> bool; + + [[nodiscard]] auto getType(const std::string &name) const -> const std::shared_ptr &; + + auto addType(const std::shared_ptr &type) -> void; + + private: + std::map> _types; +}; +} + +#endif // FILC_ENVIRONMENT_H diff --git a/include/filc/validation/ValidationVisitor.h b/include/filc/validation/ValidationVisitor.h index 00fd31f..265ee4b 100644 --- a/include/filc/validation/ValidationVisitor.h +++ b/include/filc/validation/ValidationVisitor.h @@ -25,6 +25,7 @@ #define FILC_VALIDATIONVISITOR_H #include "filc/grammar/Visitor.h" +#include "filc/validation/Environment.h" #include #include #include @@ -54,6 +55,8 @@ class ValidationContext final { return std::any_cast(_values.top().at(key)); } + auto clear() -> void; + private: std::stack> _values; }; @@ -84,6 +87,7 @@ class ValidationVisitor final : public Visitor { private: std::unique_ptr _context; + std::unique_ptr _environment; std::ostream &_out; }; } diff --git a/src/grammar/Type.cpp b/src/grammar/Type.cpp new file mode 100644 index 0000000..61f63cd --- /dev/null +++ b/src/grammar/Type.cpp @@ -0,0 +1,54 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "filc/grammar/Type.h" +#include + +using namespace filc; + +Type::Type(std::string name) : _name(std::move(name)) {} + +std::string Type::getName() const noexcept { return _name; } + +std::string Type::getDisplayName() const noexcept { return getName(); } + +PointerType::PointerType(std::shared_ptr pointed_type) : _pointed_type(std::move(pointed_type)) {} + +auto PointerType::getName() const noexcept -> std::string { return _pointed_type->getName() + "*"; } + +auto PointerType::getDisplayName() const noexcept -> std::string { return _pointed_type->getDisplayName() + "*"; } + +AliasType::AliasType(std::string name, std::shared_ptr aliased_type) + : _name(std::move(name)), _aliased_type(std::move(aliased_type)) {} + +auto AliasType::getName() const noexcept -> std::string { return _aliased_type->getName(); } + +auto AliasType::getDisplayName() const noexcept -> std::string { return _name; } + +auto operator==(const std::shared_ptr &a, const std::shared_ptr &b) -> bool { + return a->getName() == b->getName(); +} + +auto operator!=(const std::shared_ptr &a, const std::shared_ptr &b) -> bool { + return !(a == b); +} diff --git a/src/grammar/expression/Expression.cpp b/src/grammar/expression/Expression.cpp index 5005eca..4a190f9 100644 --- a/src/grammar/expression/Expression.cpp +++ b/src/grammar/expression/Expression.cpp @@ -30,3 +30,7 @@ Expression::Expression() = default; auto Expression::setPosition(const Position &position) -> void { _position = position; } auto Expression::getPosition() const -> const Position & { return _position; } + +auto Expression::setType(const std::shared_ptr &type) -> void { _type = type; } + +auto Expression::getType() const -> const std::shared_ptr & { return _type; } diff --git a/src/validation/Environment.cpp b/src/validation/Environment.cpp new file mode 100644 index 0000000..984f521 --- /dev/null +++ b/src/validation/Environment.cpp @@ -0,0 +1,67 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "filc/validation/Environment.h" +#include + +using namespace filc; + +Environment::Environment() { + addType(std::make_shared("i8")); + addType(std::make_shared("i16")); + addType(std::make_shared("i32")); + addType(std::make_shared("i64")); + addType(std::make_shared("i128")); + addType(std::make_shared("int", getType("i32"))); + + addType(std::make_shared("u8")); + addType(std::make_shared("u16")); + addType(std::make_shared("u32")); + addType(std::make_shared("u64")); + addType(std::make_shared("u128")); + addType(std::make_shared("uint", getType("u32"))); + + addType(std::make_shared("f32")); + addType(std::make_shared("f64")); + + addType(std::make_shared("bool")); + + addType(std::make_shared("char", getType("u8"))); + addType(std::make_shared(getType("char"))); +} + +auto Environment::hasType(const std::string &name) const -> bool { return _types.find(name) != _types.end(); } + +auto Environment::getType(const std::string &name) const -> const std::shared_ptr & { + if (!hasType(name)) { + throw std::logic_error("Environment doesn't have type " + name); + } + return _types.at(name); +} + +auto Environment::addType(const std::shared_ptr &type) -> void { + if (hasType(type->getDisplayName())) { + throw std::logic_error("Environment already have type " + type->getDisplayName() + " aka " + type->getName()); + } + _types[type->getDisplayName()] = type; +} diff --git a/src/validation/ValidationContext.cpp b/src/validation/ValidationContext.cpp index 1bd2d59..89a7c5a 100644 --- a/src/validation/ValidationContext.cpp +++ b/src/validation/ValidationContext.cpp @@ -40,3 +40,5 @@ auto ValidationContext::set(const std::string &key, const std::any &value) -> vo auto ValidationContext::has(const std::string &key) const -> bool { return _values.top().find(key) != _values.top().end(); } + +auto ValidationContext::clear() -> void { _values.top().clear(); } diff --git a/src/validation/ValidationVisitor.cpp b/src/validation/ValidationVisitor.cpp index 7f1bffe..33a7e8c 100644 --- a/src/validation/ValidationVisitor.cpp +++ b/src/validation/ValidationVisitor.cpp @@ -29,41 +29,72 @@ using namespace filc; -ValidationVisitor::ValidationVisitor(std::ostream &out) : _context(new ValidationContext()), _out(out) {} +ValidationVisitor::ValidationVisitor(std::ostream &out) + : _context(new ValidationContext()), _environment(new Environment()), _out(out) {} auto ValidationVisitor::visitProgram(Program *program) -> void { - for (const auto &expression : program->getExpressions()) { - _context->set("return", true); - expression->accept(this); + auto expressions = program->getExpressions(); + for (auto it = expressions.begin(); it != expressions.end(); it++) { + if (it + 1 != expressions.end()) { + _context->set("alone", true); + } + + (*it)->accept(this); + + if (it + 1 == expressions.end()) { + const auto expected = _environment->getType("int"); + const auto found_type = (*it)->getType(); + if (found_type != expected) { + auto found_type_name = found_type->getDisplayName() != found_type->getName() + ? found_type->getDisplayName() + " aka " + found_type->getName() + : found_type->getDisplayName(); + _out << Message(ERROR, + "Expected type " + expected->getDisplayName() + " aka " + expected->getName() + + " but got " + found_type_name, + (*it)->getPosition(), ERROR_COLOR); + } + } + + _context->clear(); } } auto ValidationVisitor::visitBooleanLiteral(BooleanLiteral *literal) -> void { - if (_context->has("return") && _context->get("return")) { + literal->setType(_environment->getType("bool")); + + if (_context->has("alone") && _context->get("alone")) { _out << Message(WARNING, "Boolean value not used", literal->getPosition(), WARNING_COLOR); } } auto ValidationVisitor::visitIntegerLiteral(IntegerLiteral *literal) -> void { - if (_context->has("return") && _context->get("return")) { + literal->setType(_environment->getType("int")); + + if (_context->has("alone") && _context->get("alone")) { _out << Message(WARNING, "Integer value not used", literal->getPosition(), WARNING_COLOR); } } auto ValidationVisitor::visitFloatLiteral(FloatLiteral *literal) -> void { - if (_context->has("return") && _context->get("return")) { + literal->setType(_environment->getType("f64")); + + if (_context->has("alone") && _context->get("alone")) { _out << Message(WARNING, "Float value not used", literal->getPosition(), WARNING_COLOR); } } auto ValidationVisitor::visitCharacterLiteral(CharacterLiteral *literal) -> void { - if (_context->has("return") && _context->get("return")) { + literal->setType(_environment->getType("char")); + + if (_context->has("alone") && _context->get("alone")) { _out << Message(WARNING, "Character value not used", literal->getPosition(), WARNING_COLOR); } } auto ValidationVisitor::visitStringLiteral(StringLiteral *literal) -> void { - if (_context->has("return") && _context->get("return")) { + literal->setType(_environment->getType("char*")); + + if (_context->has("alone") && _context->get("alone")) { _out << Message(WARNING, "String value not used", literal->getPosition(), WARNING_COLOR); } } diff --git a/tests/unit/Fixtures/validation/boolean.fil b/tests/unit/Fixtures/validation/boolean.fil index 27ba77d..033cb67 100644 --- a/tests/unit/Fixtures/validation/boolean.fil +++ b/tests/unit/Fixtures/validation/boolean.fil @@ -1 +1,2 @@ true +0 diff --git a/tests/unit/Fixtures/validation/character.fil b/tests/unit/Fixtures/validation/character.fil index a87f815..a6c96f8 100644 --- a/tests/unit/Fixtures/validation/character.fil +++ b/tests/unit/Fixtures/validation/character.fil @@ -1 +1,2 @@ 'g' +0 diff --git a/tests/unit/Fixtures/validation/float.fil b/tests/unit/Fixtures/validation/float.fil index b3d791d..064a417 100644 --- a/tests/unit/Fixtures/validation/float.fil +++ b/tests/unit/Fixtures/validation/float.fil @@ -1 +1,2 @@ 4.6 +0 diff --git a/tests/unit/Fixtures/validation/integer.fil b/tests/unit/Fixtures/validation/integer.fil index 48082f7..368283e 100644 --- a/tests/unit/Fixtures/validation/integer.fil +++ b/tests/unit/Fixtures/validation/integer.fil @@ -1 +1,2 @@ 12 +0 diff --git a/tests/unit/Fixtures/validation/invalid_program.fil b/tests/unit/Fixtures/validation/invalid_program.fil new file mode 100644 index 0000000..908d586 --- /dev/null +++ b/tests/unit/Fixtures/validation/invalid_program.fil @@ -0,0 +1,2 @@ +// Its last expression is not int +"Hello" diff --git a/tests/unit/Fixtures/validation/string.fil b/tests/unit/Fixtures/validation/string.fil index 3580093..fd91746 100644 --- a/tests/unit/Fixtures/validation/string.fil +++ b/tests/unit/Fixtures/validation/string.fil @@ -1 +1,2 @@ "hello" +0 diff --git a/tests/unit/Fixtures/validation/valid_program.fil b/tests/unit/Fixtures/validation/valid_program.fil new file mode 100644 index 0000000..44fb636 --- /dev/null +++ b/tests/unit/Fixtures/validation/valid_program.fil @@ -0,0 +1,2 @@ +// Its last expression is int +0 diff --git a/tests/unit/grammar/TypeTest.cpp b/tests/unit/grammar/TypeTest.cpp new file mode 100644 index 0000000..487bb37 --- /dev/null +++ b/tests/unit/grammar/TypeTest.cpp @@ -0,0 +1,55 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include + +TEST(Type, getName) { + filc::Type type("my_type"); + ASSERT_STREQ("my_type", type.getName().c_str()); +} + +TEST(Type, getDisplayName) { + filc::Type type("another_type"); + ASSERT_STREQ("another_type", type.getDisplayName().c_str()); +} + +TEST(PointerType, getName) { + filc::PointerType type(std::make_shared("int")); + ASSERT_STREQ("int*", type.getName().c_str()); +} + +TEST(PointerType, getDisplayName) { + filc::PointerType type(std::make_shared("int")); + ASSERT_STREQ("int*", type.getDisplayName().c_str()); +} + +TEST(AliasType, getName) { + filc::AliasType type("char", std::make_shared("u8")); + ASSERT_STREQ("u8", type.getName().c_str()); +} + +TEST(AliasType, getDisplayName) { + filc::AliasType type("char", std::make_shared("u8")); + ASSERT_STREQ("char", type.getDisplayName().c_str()); +} diff --git a/tests/unit/validation/EnvironmentTest.cpp b/tests/unit/validation/EnvironmentTest.cpp new file mode 100644 index 0000000..561048d --- /dev/null +++ b/tests/unit/validation/EnvironmentTest.cpp @@ -0,0 +1,57 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include + +TEST(Environment, constructor) { + filc::Environment env; + ASSERT_TRUE(env.hasType("i8")); + ASSERT_TRUE(env.hasType("i8")); + ASSERT_TRUE(env.hasType("i16")); + ASSERT_TRUE(env.hasType("i32")); + ASSERT_TRUE(env.hasType("i64")); + ASSERT_TRUE(env.hasType("i128")); + ASSERT_TRUE(env.hasType("int")); + ASSERT_TRUE(env.hasType("u8")); + ASSERT_TRUE(env.hasType("u16")); + ASSERT_TRUE(env.hasType("u32")); + ASSERT_TRUE(env.hasType("u64")); + ASSERT_TRUE(env.hasType("u128")); + ASSERT_TRUE(env.hasType("uint")); + ASSERT_TRUE(env.hasType("f32")); + ASSERT_TRUE(env.hasType("f64")); + ASSERT_TRUE(env.hasType("bool")); + ASSERT_TRUE(env.hasType("char")); + ASSERT_TRUE(env.hasType("char*")); +} + +TEST(Environment, Type) { + filc::Environment env; + ASSERT_FALSE(env.hasType("custom")); + ASSERT_THROW(env.getType("custom"), std::logic_error); + env.addType(std::make_shared("custom")); + ASSERT_THROW(env.addType(std::make_shared("custom")), std::logic_error); + ASSERT_TRUE(env.hasType("custom")); + ASSERT_STREQ("custom", env.getType("custom")->getName().c_str()); +} diff --git a/tests/unit/validation/ValidationContextTest.cpp b/tests/unit/validation/ValidationContextTest.cpp index eb108c7..40b67df 100644 --- a/tests/unit/validation/ValidationContextTest.cpp +++ b/tests/unit/validation/ValidationContextTest.cpp @@ -93,3 +93,11 @@ TEST(ValidationContext, get_set_object) { ASSERT_TRUE(context.has("object_value")); ASSERT_TRUE(value.equals(context.get("object_value"))); } + +TEST(ValidationContext, clear) { + filc::ValidationContext context; + context.set("key", "value"); + ASSERT_TRUE(context.has("key")); + context.clear(); + ASSERT_FALSE(context.has("key")); +} diff --git a/tests/unit/validation/ValidationVisitorTest.cpp b/tests/unit/validation/ValidationVisitorTest.cpp index 2d6b288..a8151eb 100644 --- a/tests/unit/validation/ValidationVisitorTest.cpp +++ b/tests/unit/validation/ValidationVisitorTest.cpp @@ -22,6 +22,7 @@ * SOFTWARE. */ #include +#include #include #include #include @@ -36,6 +37,21 @@ using namespace ::testing; #define VALIDATION_FIXTURES FIXTURES_PATH "/validation" +TEST(ValidationVisitor, visitProgram_valid) { + VISITOR; + const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/valid_program.fil"); + program->accept(&visitor); + ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), IsEmpty()); +} + +TEST(ValidationVisitor, visitProgram_invalid) { + VISITOR; + const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/invalid_program.fil"); + program->accept(&visitor); + ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), + HasSubstr("Expected type int aka i32 but got char* aka u8*")); +} + TEST(ValidationVisitor, visitBooleanLiteral) { VISITOR; const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/boolean.fil"); @@ -48,6 +64,7 @@ TEST(ValidationVisitor, visitIntegerLiteral) { const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/integer.fil"); program->accept(&visitor); ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), HasSubstr("Integer value not used")); + ASSERT_STREQ("int", program->getExpressions()[0]->getType()->getDisplayName().c_str()); } TEST(ValidationVisitor, visitFloatLiteral) { @@ -55,6 +72,7 @@ TEST(ValidationVisitor, visitFloatLiteral) { const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/float.fil"); program->accept(&visitor); ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), HasSubstr("Float value not used")); + ASSERT_STREQ("f64", program->getExpressions()[0]->getType()->getDisplayName().c_str()); } TEST(ValidationVisitor, visitCharacterLiteral) { @@ -62,6 +80,7 @@ TEST(ValidationVisitor, visitCharacterLiteral) { const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/character.fil"); program->accept(&visitor); ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), HasSubstr("Character value not used")); + ASSERT_STREQ("char", program->getExpressions()[0]->getType()->getDisplayName().c_str()); } TEST(ValidationVisitor, visitStringLiteral) { @@ -69,6 +88,7 @@ TEST(ValidationVisitor, visitStringLiteral) { const auto program = filc::ParserProxy::parse(VALIDATION_FIXTURES "/string.fil"); program->accept(&visitor); ASSERT_THAT(std::string(std::istreambuf_iterator(ss), {}), HasSubstr("String value not used")); + ASSERT_STREQ("char*", program->getExpressions()[0]->getType()->getDisplayName().c_str()); } TEST(ValidationVisitor, visitVariableDeclaration) {