Finish up the basic implementation of Call expr

This commit is contained in:
Sameer Rahmani 2021-05-09 12:21:26 +01:00
parent f2049b5ae8
commit 0ce47a0b6a
9 changed files with 52 additions and 29 deletions

View File

@ -50,6 +50,8 @@ public:
Call(reader::LocationRange &loc, Node &target, Ast &params)
: Expression(loc), target(target), params(params){};
Call(Call &) = delete;
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);

View File

@ -49,6 +49,8 @@ public:
Def(reader::LocationRange &loc, llvm::StringRef binding, Node &v)
: Expression(loc), binding(binding), value(v){};
Def(Def &d) = delete;
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);

View File

@ -53,6 +53,8 @@ public:
Fn(reader::LocationRange &loc, List &args, Ast body)
: Expression(loc), args(args), body(body){};
Fn(Fn &f) = delete;
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);

View File

@ -44,6 +44,8 @@ public:
Symbol(reader::LocationRange &loc, llvm::StringRef name)
: Expression(loc), name(name){};
Symbol(Symbol &s) : Expression(s.location) { this->name = s.name; }
ExprType getType() const;
std::string toString() const;

View File

@ -12,6 +12,7 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/exprs/def.h"
"${INCLUDE_DIR}/serene/exprs/fn.h"
"${INCLUDE_DIR}/serene/exprs/traits.h"
"${INCLUDE_DIR}/serene/exprs/call.h"
# Reader
"${INCLUDE_DIR}/serene/reader/reader.h"
@ -40,8 +41,10 @@ add_library(serene
exprs/expression.cpp
exprs/def.cpp
exprs/fn.cpp
context.cpp
exprs/call.cpp
context.cpp
serene.cpp
namespace.cpp

View File

@ -24,11 +24,13 @@
#include "serene/exprs/call.h"
#include "serene/errors/error.h"
#include "serene/exprs/def.h"
#include "serene/exprs/expression.h"
#include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
#include "serene/reader/semantics.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
@ -48,7 +50,7 @@ bool Call::classof(const Expression *e) {
};
MaybeNode Call::make(SereneContext &ctx, List *list) {
assert((list->count() == 0) && "Empty call? Seriously ?");
assert((list->count() != 0) && "Empty call? Seriously ?");
// Let's find out what is the first element of the list
auto maybeFirst = list->elements[0]->analyze(ctx);
@ -72,20 +74,26 @@ MaybeNode Call::make(SereneContext &ctx, List *list) {
case ExprType::Symbol: {
auto *sym = llvm::dyn_cast<Symbol>(first.get());
if (!sym) {
llvm_unreachable("Couldn't case to Symbol while the type is symbol!");
}
// TODO: Lookup the symbol in the namespace via a method that looks
// into the current environment.
auto maybeResult = ctx.getCurrentNS()->semanticEnv.lookup(sym->name);
if (!maybeResult) {
return makeErrorful<Node>(
sym->location, &errors::CantResolveSymbol,
llvm::formatv("Can't resolve the symbol '{0}'!", sym->name));
std::string msg =
llvm::formatv("Can't resolve the symbol '{0}'!", sym->name);
return makeErrorful<Node>(sym->location, &errors::CantResolveSymbol, msg);
}
targetNode = maybeResult.getValue();
break;
}
case ExprType::Def:
// If the first element was a Call itself we need to just chain it
// with a new call. It would be something like `((blah 1) 4)`. `blah`
// should return a callable expression itself, which we need to let
@ -100,10 +108,10 @@ MaybeNode Call::make(SereneContext &ctx, List *list) {
// Otherwise we don't know how to call the first element.
default: {
return makeErrorful<Node>(
first, &errors::DontKnowHowToCallNode,
llvm::formatv("Don't know how to call a '{0}'",
stringifyExprType(first->getType())));
std::string msg = llvm::formatv("Don't know how to call a '{0}'",
stringifyExprType(first->getType()));
return makeErrorful<Node>(first->location, &errors::DontKnowHowToCallNode,
msg);
}
};

View File

@ -28,6 +28,7 @@
#include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
#include "serene/reader/semantics.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
@ -42,18 +43,13 @@ std::string Fn::toString() const {
this->body.empty() ? "<>" : astToString(&this->body));
}
MaybeNode Fn::analyze(SereneContext &ctx) {
return MaybeNode::success(nullptr);
};
MaybeNode Fn::analyze(SereneContext &ctx) { return EmptyNode; };
bool Fn::classof(const Expression *e) { return e->getType() == ExprType::Fn; };
MaybeNode Fn::make(SereneContext &ctx, List *list) {
// TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() < 2) {
// return MaybeNode::error(makeAndCast<errors::Error>(
// list->elements[0]->location, &errors::FnNoArgsList,
// "The argument list is mandatory."));
return makeErrorful<Node>(list->elements[0]->location,
&errors::FnNoArgsList,
"The argument list is mandatory.");
@ -69,9 +65,6 @@ MaybeNode Fn::make(SereneContext &ctx, List *list) {
std::string msg =
llvm::formatv("Arguments of a function has to be a list, got '{0}'",
stringifyExprType(list->elements[1]->getType()));
// return MaybeNode::error(makeAndCast<errors::Error>(
// list->elements[1]->location, &errors::FnArgsMustBeList, msg));
return makeErrorful<Node>(list->elements[1]->location,
&errors::FnArgsMustBeList, msg);
}

View File

@ -24,7 +24,9 @@
#include "serene/exprs/list.h"
#include "serene/errors/error.h"
#include "serene/exprs/call.h"
#include "serene/exprs/def.h"
#include "serene/exprs/expression.h"
#include "serene/exprs/fn.h"
#include "serene/exprs/symbol.h"
#include "llvm/Support/Casting.h"
@ -35,7 +37,10 @@
namespace serene {
namespace exprs {
List::List(const List &l) : Expression(l.location){};
List::List(const List &l) : Expression(l.location) {
this->elements = l.elements;
};
List::List(const reader::LocationRange &loc, Node &e) : Expression(loc) {
elements.push_back(e);
};
@ -72,9 +77,11 @@ MaybeNode List::analyze(SereneContext &ctx) {
}
}
}
return Call::make(ctx, this);
}
return MaybeNode::success(nullptr);
return EmptyNode;
};
bool List::classof(const Expression *e) {

View File

@ -130,7 +130,8 @@ TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Symbol a> <Symbol a> <Symbol a>>");
"<Fn Anonymous <List <Symbol a> <Symbol b> <Symbol c>> to <Symbol a> "
"<Symbol a> <Symbol a>>");
ast = reader::read("(fn () a b)");
afterAst = reader::analyze(ctx, ast.getValue());
@ -142,15 +143,17 @@ TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Fn Anonymous <List -> to <Symbol x>> "
"<Symbol z>>");
"<Fn Anonymous <List <Symbol x>> to <Fn Anonymous <List <Symbol y>> "
"to <Symbol x>> <Symbol z>>"
);
ast = reader::read("(fn (x) (def a b) (def b c))");
afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst);
CHECK(
astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Def a -> <Symbol b>> <Def b -> <Symbol c>>>");
CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List <Symbol x>> to <Def a -> <Symbol b>> <Def b -> "
"<Symbol c>>>");
}
TEST_CASE("Complex semantic analysis", "[semantic]") {
@ -159,11 +162,12 @@ TEST_CASE("Complex semantic analysis", "[semantic]") {
auto ast =
reader::read("(def a (fn (x) x))\n((def b (fn (x) (fn (y) y))))\n\n");
auto afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) ==
"<Def a -> <Fn Anonymous <List -> to <Symbol x>>> <List <List "
"<Symbol def> <Symbol b> <List <Symbol fn> <List <Symbol x>> <List "
"<Symbol fn> <List <Symbol y>> <Symbol y>>>>>");
"<Def a -> <Fn Anonymous <List <Symbol x>> to <Symbol x>>> <Call <Def "
"b -> <Fn Anonymous <List <Symbol x>> to <Fn Anonymous <List <Symbol "
"y>> to <Symbol y>>>> >");
}
} // namespace exprs
} // namespace serene