Analyze the value in the 'def' form

This commit is contained in:
Sameer Rahmani 2021-04-24 19:10:18 +01:00
parent 8242249dca
commit 4aee3413ea
6 changed files with 54 additions and 14 deletions

View File

@ -55,8 +55,12 @@ public:
static bool classof(const Expression *e);
/// Create a Def node out a list. The list should contain the
/// correct `def` form like `(def blah value)`.
static maybe_node make(List *);
/// correct `def` form like `(def blah value)`. This function
/// is supposed to be used in the semantic analysis phase.
///
/// \param ctx The semantic analysis context object.
/// \param list the list containing the `def` form
static maybe_node make(reader::SemanticContext &ctx, List *list);
~Def() = default;
};

View File

@ -60,8 +60,13 @@ public:
/// Creates a function node out of a function definition
/// in a list. the list has to contain the correct definition
/// of a function, for exmaple: `(fn (args1 arg2) body)`
static maybe_node make(List *);
/// of a function, for exmaple: `(fn (args1 arg2) body)`.This function
/// is supposed to be used in the semantic analysis phase.
///
/// \param ctx The semantic analysis context object.
/// \param list the list containing the `fn` form
static maybe_node make(reader::SemanticContext &ctx, List *list);
~Fn() = default;
};

View File

@ -46,26 +46,48 @@ bool Def::classof(const Expression *e) {
return e->getType() == ExprType::Def;
};
maybe_node Def::make(List *list) {
maybe_node Def::make(reader::SemanticContext &ctx, 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 {0}", list->count());
return Result<node>::success(makeAndCast<errors::Error>(
&errors::DefWrongNumberOfArgs, list->elements[0], msg));
}
// Make sure that the list starts with a `def`
Symbol *defSym = llvm::dyn_cast<Symbol>(list->elements[0].get());
assert((defSym && defSym->name == "def") &&
"The first element of the list should be a 'def'.");
// Make sure that the first argument is a Symbol
Symbol *binding = llvm::dyn_cast<Symbol>(list->elements[1].get());
if (!binding) {
return Result<node>::success(makeAndCast<errors::Error>(
&errors::DefExpectSymbol, list->elements[1], ""));
}
node def = exprs::make<Def>(list->location, binding->name, list->elements[2]);
// Analyze the value
maybe_node value = list->elements[2]->analyze(ctx);
node analyzedValue;
if (value) {
// Success value
auto &valueNode = value.getValue();
if (valueNode) {
// A rewrite is necessary
analyzedValue = valueNode;
} else {
// no rewrite
analyzedValue = list->elements[2];
}
} else {
// Error value
return value;
}
node def = exprs::make<Def>(list->location, binding->name, analyzedValue);
return Result<node>::success(def);
};
} // namespace exprs

View File

@ -47,7 +47,7 @@ maybe_node Fn::analyze(reader::SemanticContext &ctx) {
bool Fn::classof(const Expression *e) { return e->getType() == ExprType::Fn; };
maybe_node Fn::make(List *list) {
maybe_node Fn::make(reader::SemanticContext &ctx, List *list) {
// TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() < 2) {
std::string msg =

View File

@ -64,11 +64,11 @@ maybe_node List::analyze(reader::SemanticContext &ctx) {
if (sym) {
if (sym->name == "def") {
return Def::make(this);
return Def::make(ctx, this);
}
if (sym->name == "fn") {
return Fn::make(this);
return Fn::make(ctx, this);
}
}

View File

@ -100,6 +100,12 @@ TEST_CASE("List semantic analysis of 'def'", "[semantic]") {
afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Def a -> <Symbol b>>");
ast = reader::read("(def a (fn () a))");
afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) ==
"<Def a -> <Fn Anonymous <List -> to <Symbol a>>>");
}
TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
@ -107,22 +113,25 @@ TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
auto ast = reader::read("(fn)");
auto afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Error E3: The argument list is mandatory.>");
CHECK(astToString(&afterAst.getValue()) ==
"<Error E3: The argument list is mandatory.>");
ast = reader::read("(fn ())");
afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Fn Anonymous <List -> to <>>");
CHECK(astToString(&afterAst.getValue()) == "<Fn Anonymous <List -> to <>>");
ast = reader::read("(fn (a b c) a a a)");
afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Fn Anonymous <List -> to <Symbol a> <Symbol a> <Symbol a>>");
CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Symbol a> <Symbol a> <Symbol a>>");
ast = reader::read("(fn () a b)");
afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Fn Anonymous <List -> to <Symbol a> <Symbol b>>");
CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Symbol a> <Symbol b>>");
}
} // namespace exprs
} // namespace serene