Analyze the value in the 'def' form
This commit is contained in:
parent
8242249dca
commit
4aee3413ea
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue