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); static bool classof(const Expression *e);
/// Create a Def node out a list. The list should contain the /// Create a Def node out a list. The list should contain the
/// correct `def` form like `(def blah value)`. /// correct `def` form like `(def blah value)`. This function
static maybe_node make(List *); /// 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; ~Def() = default;
}; };

View File

@ -60,8 +60,13 @@ public:
/// Creates a function node out of a function definition /// Creates a function node out of a function definition
/// in a list. the list has to contain the correct definition /// in a list. the list has to contain the correct definition
/// of a function, for exmaple: `(fn (args1 arg2) body)` /// of a function, for exmaple: `(fn (args1 arg2) body)`.This function
static maybe_node make(List *); /// 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; ~Fn() = default;
}; };

View File

@ -46,26 +46,48 @@ bool Def::classof(const Expression *e) {
return e->getType() == ExprType::Def; 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) // TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() != 3) { if (list->count() != 3) {
std::string msg = llvm::formatv("Expected 3 got {0}", list->count()); std::string msg = llvm::formatv("Expected 3 got {0}", list->count());
return Result<node>::success(makeAndCast<errors::Error>( return Result<node>::success(makeAndCast<errors::Error>(
&errors::DefWrongNumberOfArgs, list->elements[0], msg)); &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()); Symbol *defSym = llvm::dyn_cast<Symbol>(list->elements[0].get());
assert((defSym && defSym->name == "def") && assert((defSym && defSym->name == "def") &&
"The first element of the list should be a '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()); Symbol *binding = llvm::dyn_cast<Symbol>(list->elements[1].get());
if (!binding) { if (!binding) {
return Result<node>::success(makeAndCast<errors::Error>( return Result<node>::success(makeAndCast<errors::Error>(
&errors::DefExpectSymbol, list->elements[1], "")); &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); return Result<node>::success(def);
}; };
} // namespace exprs } // 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; }; 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) // TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() < 2) { if (list->count() < 2) {
std::string msg = std::string msg =

View File

@ -64,11 +64,11 @@ maybe_node List::analyze(reader::SemanticContext &ctx) {
if (sym) { if (sym) {
if (sym->name == "def") { if (sym->name == "def") {
return Def::make(this); return Def::make(ctx, this);
} }
if (sym->name == "fn") { 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()); afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst); REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == "<Def a -> <Symbol b>>"); 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]") { 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 ast = reader::read("(fn)");
auto afterAst = analyzer.analyze(ast.getValue()); auto afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst); 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 ())"); ast = reader::read("(fn ())");
afterAst = analyzer.analyze(ast.getValue()); afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst); 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)"); ast = reader::read("(fn (a b c) a a a)");
afterAst = analyzer.analyze(ast.getValue()); afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst); 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)"); ast = reader::read("(fn () a b)");
afterAst = analyzer.analyze(ast.getValue()); afterAst = analyzer.analyze(ast.getValue());
REQUIRE(afterAst); 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 exprs
} // namespace serene } // namespace serene