Finish up the basic implementation of Call expr
This commit is contained in:
parent
f2049b5ae8
commit
0ce47a0b6a
|
@ -50,6 +50,8 @@ public:
|
||||||
Call(reader::LocationRange &loc, Node &target, Ast ¶ms)
|
Call(reader::LocationRange &loc, Node &target, Ast ¶ms)
|
||||||
: 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 &);
|
||||||
|
|
|
@ -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 &);
|
||||||
|
|
|
@ -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 &);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue