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) Call(reader::LocationRange &loc, Node &target, Ast &params)
: Expression(loc), target(target), params(params){}; : Expression(loc), target(target), params(params){};
Call(Call &) = delete;
ExprType getType() const; ExprType getType() const;
std::string toString() const; std::string toString() const;
MaybeNode analyze(SereneContext &); MaybeNode analyze(SereneContext &);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,7 +24,9 @@
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/errors/error.h" #include "serene/errors/error.h"
#include "serene/exprs/call.h"
#include "serene/exprs/def.h" #include "serene/exprs/def.h"
#include "serene/exprs/expression.h"
#include "serene/exprs/fn.h" #include "serene/exprs/fn.h"
#include "serene/exprs/symbol.h" #include "serene/exprs/symbol.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
@ -35,7 +37,10 @@
namespace serene { namespace serene {
namespace exprs { 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) { List::List(const reader::LocationRange &loc, Node &e) : Expression(loc) {
elements.push_back(e); 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) { 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()); afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst); REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == 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)"); ast = reader::read("(fn () a b)");
afterAst = reader::analyze(ctx, ast.getValue()); afterAst = reader::analyze(ctx, ast.getValue());
@ -142,15 +143,17 @@ TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
afterAst = reader::analyze(ctx, ast.getValue()); afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst); REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == CHECK(astToString(&afterAst.getValue()) ==
"<Fn Anonymous <List -> to <Fn Anonymous <List -> to <Symbol x>> " "<Fn Anonymous <List <Symbol x>> to <Fn Anonymous <List <Symbol y>> "
"<Symbol z>>"); "to <Symbol x>> <Symbol z>>"
);
ast = reader::read("(fn (x) (def a b) (def b c))"); ast = reader::read("(fn (x) (def a b) (def b c))");
afterAst = reader::analyze(ctx, ast.getValue()); afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst); REQUIRE(afterAst);
CHECK( CHECK(astToString(&afterAst.getValue()) ==
astToString(&afterAst.getValue()) == "<Fn Anonymous <List <Symbol x>> to <Def a -> <Symbol b>> <Def b -> "
"<Fn Anonymous <List -> to <Def a -> <Symbol b>> <Def b -> <Symbol c>>>"); "<Symbol c>>>");
} }
TEST_CASE("Complex semantic analysis", "[semantic]") { TEST_CASE("Complex semantic analysis", "[semantic]") {
@ -159,11 +162,12 @@ TEST_CASE("Complex semantic analysis", "[semantic]") {
auto ast = auto ast =
reader::read("(def a (fn (x) x))\n((def b (fn (x) (fn (y) y))))\n\n"); reader::read("(def a (fn (x) x))\n((def b (fn (x) (fn (y) y))))\n\n");
auto afterAst = reader::analyze(ctx, ast.getValue()); auto afterAst = reader::analyze(ctx, ast.getValue());
REQUIRE(afterAst); REQUIRE(afterAst);
CHECK(astToString(&afterAst.getValue()) == CHECK(astToString(&afterAst.getValue()) ==
"<Def a -> <Fn Anonymous <List -> to <Symbol x>>> <List <List " "<Def a -> <Fn Anonymous <List <Symbol x>> to <Symbol x>>> <Call <Def "
"<Symbol def> <Symbol b> <List <Symbol fn> <List <Symbol x>> <List " "b -> <Fn Anonymous <List <Symbol x>> to <Fn Anonymous <List <Symbol "
"<Symbol fn> <List <Symbol y>> <Symbol y>>>>>"); "y>> to <Symbol y>>>> >");
} }
} // namespace exprs } // namespace exprs
} // namespace serene } // namespace serene