Setup the minimal semantic analysis foundation

This commit is contained in:
Sameer Rahmani 2021-04-22 10:20:15 +01:00
parent f614d35b7f
commit 806987b0ad
8 changed files with 60 additions and 17 deletions

View File

@ -34,7 +34,7 @@ namespace errors {
enum ErrID { enum ErrID {
E0000, E0000,
E0001, E0001,
E0002,
}; };
struct ErrorVariant { struct ErrorVariant {
@ -52,8 +52,13 @@ static ErrorVariant
DefExpectSymbol(E0001, "The first argument to 'def' has to be a Symbol.", DefExpectSymbol(E0001, "The first argument to 'def' has to be a Symbol.",
""); "");
static std::map<ErrID, ErrorVariant *> ErrDesc = {{E0000, &UnknownError}, static ErrorVariant DefWrongNumberOfArgs(
{E0001, &DefExpectSymbol}}; E0002, "Wrong number of arguments is passed to the 'def' form.", "");
static std::map<ErrID, ErrorVariant *> ErrDesc = {
{E0000, &UnknownError},
{E0001, &DefExpectSymbol},
{E0002, &DefWrongNumberOfArgs}};
} // namespace errors } // namespace errors
} // namespace serene } // namespace serene

View File

@ -53,7 +53,7 @@ public:
maybe_node analyze(reader::SemanticContext &); maybe_node analyze(reader::SemanticContext &);
static bool classof(const Expression *e); static bool classof(const Expression *e);
static std::shared_ptr<errors::Error> isValid(const List *); static std::shared_ptr<errors::Error> isValid(List *);
~Def() = default; ~Def() = default;
}; };

View File

@ -107,6 +107,7 @@ std::shared_ptr<T> makeAndCast(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...); return std::make_shared<T>(std::forward<Args>(args)...);
}; };
std::string toString(ast &);
void dump(ast &); void dump(ast &);
} // namespace exprs } // namespace exprs

View File

@ -33,9 +33,7 @@ serene::exprs::ExprType Error::getType() const {
}; };
std::string Error::toString() const { std::string Error::toString() const {
return llvm::formatv( return llvm::formatv("<Error E{0}: {1}>", this->variant->id, this->message);
"<Error [loc: {0} | {1}]: E{2}: {3}>", this->location.start.toString(),
this->location.end.toString(), this->variant->id, this->message);
} }
serene::exprs::maybe_node Error::analyze(reader::SemanticContext &ctx) { serene::exprs::maybe_node Error::analyze(reader::SemanticContext &ctx) {

View File

@ -23,7 +23,9 @@
*/ */
#include "serene/exprs/def.h" #include "serene/exprs/def.h"
#include "serene/errors/error.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormatVariadic.h"
namespace serene { namespace serene {
@ -44,7 +46,21 @@ bool Def::classof(const Expression *e) {
return e->getType() == ExprType::Def; return e->getType() == ExprType::Def;
}; };
std::shared_ptr<errors::Error> Def::isValid(const List *list) { std::shared_ptr<errors::Error> Def::isValid(List *list) {
// TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() != 3) {
std::string msg = llvm::formatv("Expected 3 got {}", list->count());
return makeAndCast<errors::Error>(&errors::DefWrongNumberOfArgs,
list->elements[0], msg);
}
Symbol *binding = llvm::dyn_cast<Symbol>(list->elements[1].get());
if (!binding) {
return makeAndCast<errors::Error>(&errors::DefExpectSymbol,
list->elements[1], "");
}
return nullptr; return nullptr;
}; };
} // namespace exprs } // namespace exprs

View File

@ -28,16 +28,22 @@
namespace serene { namespace serene {
namespace exprs { namespace exprs {
/// Dump the given AST tree to the standard out std::string toString(ast &tree) {
void dump(ast &tree) { if (tree.size() == 0) {
std::string result = ""; return "";
for (auto &node : tree) {
result = llvm::formatv("{0} {1}", result, node->toString());
} }
llvm::outs() << result << "\n"; std::string result = tree.at(0)->toString();
};
for (unsigned int i = 1; i < tree.size(); i++) {
result = llvm::formatv("{0} {1}", result, tree.at(i)->toString());
}
return result;
}
/// Dump the given AST tree to the standard out
void dump(ast &tree) { llvm::outs() << toString(tree) << "\n"; };
} // namespace exprs } // namespace exprs
} // namespace serene } // namespace serene

View File

@ -41,7 +41,7 @@ TEST_CASE("Error Expression", "[expression]") {
exprs::node err = exprs::make<Error>(&DefExpectSymbol, sym, "Something Failed"); exprs::node err = exprs::make<Error>(&DefExpectSymbol, sym, "Something Failed");
REQUIRE(err->getType() == exprs::ExprType::Error); REQUIRE(err->getType() == exprs::ExprType::Error);
CHECK(err->toString() == "<Error [loc: 2:20:40 | 3:30:80]: E1: Something Failed>"); CHECK(err->toString() == "<Error E1: Something Failed>");
auto error = llvm::dyn_cast<Error>(err.get()); auto error = llvm::dyn_cast<Error>(err.get());
CHECK(error->target == sym); CHECK(error->target == sym);

View File

@ -23,7 +23,10 @@
*/ */
#include "../test_helpers.cpp.inc" #include "../test_helpers.cpp.inc"
#include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/reader/reader.h"
#include "serene/reader/semantics.h"
#include "serene/exprs/symbol.h" #include "serene/exprs/symbol.h"
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
@ -75,5 +78,19 @@ TEST_CASE("List Expression", "[expression]") {
} }
}; };
TEST_CASE("List semantic analysis", "[semantic]") {
reader::Semantics analyzer;
auto r = new reader::Reader("(def (a b) 4)");
auto ast = r->read().getValue();
//auto &ast = maybeAst.getValue();
auto afterAst = analyzer.analyze(ast);
REQUIRE(afterAst);
CHECK(toString(afterAst.getValue()) == "<Error E1: >");
delete r;
}
} // namespace exprs } // namespace exprs
} // namespace serene } // namespace serene