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 {
E0000,
E0001,
E0002,
};
struct ErrorVariant {
@ -52,8 +52,13 @@ static ErrorVariant
DefExpectSymbol(E0001, "The first argument to 'def' has to be a Symbol.",
"");
static std::map<ErrID, ErrorVariant *> ErrDesc = {{E0000, &UnknownError},
{E0001, &DefExpectSymbol}};
static ErrorVariant DefWrongNumberOfArgs(
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 serene

View File

@ -53,7 +53,7 @@ public:
maybe_node analyze(reader::SemanticContext &);
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;
};

View File

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

View File

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

View File

@ -23,7 +23,9 @@
*/
#include "serene/exprs/def.h"
#include "serene/errors/error.h"
#include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
@ -44,7 +46,21 @@ bool Def::classof(const Expression *e) {
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;
};
} // namespace exprs

View File

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

View File

@ -41,7 +41,7 @@ TEST_CASE("Error Expression", "[expression]") {
exprs::node err = exprs::make<Error>(&DefExpectSymbol, sym, "Something Failed");
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());
CHECK(error->target == sym);

View File

@ -23,7 +23,10 @@
*/
#include "../test_helpers.cpp.inc"
#include "serene/exprs/expression.h"
#include "serene/exprs/list.h"
#include "serene/reader/reader.h"
#include "serene/reader/semantics.h"
#include "serene/exprs/symbol.h"
#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 serene