2021-04-24 14:39:43 +01:00
|
|
|
/*
|
2021-10-12 20:51:03 +01:00
|
|
|
* Serene Programming Language
|
2021-04-24 14:39:43 +01:00
|
|
|
*
|
2021-10-12 20:51:03 +01:00
|
|
|
* Copyright (c) 2019-2021 Sameer Rahmani <lxsameer@gnu.org>
|
2021-04-24 14:39:43 +01:00
|
|
|
*
|
2021-10-12 20:51:03 +01:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 2.
|
2021-04-24 14:39:43 +01:00
|
|
|
*
|
2021-10-12 20:51:03 +01:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2021-04-24 14:39:43 +01:00
|
|
|
*
|
2021-10-12 20:51:03 +01:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2021-04-24 14:39:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "serene/exprs/fn.h"
|
2021-06-13 22:58:46 +01:00
|
|
|
|
2021-04-24 14:39:43 +01:00
|
|
|
#include "serene/errors/error.h"
|
|
|
|
#include "serene/exprs/expression.h"
|
|
|
|
#include "serene/exprs/list.h"
|
|
|
|
#include "serene/exprs/symbol.h"
|
2021-04-24 20:18:33 +01:00
|
|
|
#include "serene/reader/semantics.h"
|
2021-06-23 20:34:57 +01:00
|
|
|
#include "serene/slir/dialect.h"
|
|
|
|
#include "serene/slir/utils.h"
|
2021-06-13 22:58:46 +01:00
|
|
|
|
2021-06-23 20:34:57 +01:00
|
|
|
#include <llvm/Support/Casting.h>
|
|
|
|
#include <llvm/Support/FormatVariadic.h>
|
|
|
|
#include <mlir/IR/Block.h>
|
2021-09-23 19:24:51 +01:00
|
|
|
#include <mlir/IR/BuiltinAttributes.h>
|
2021-04-24 14:39:43 +01:00
|
|
|
|
2021-10-17 14:33:16 +01:00
|
|
|
#include <utility>
|
|
|
|
|
2021-04-24 14:39:43 +01:00
|
|
|
namespace serene {
|
|
|
|
namespace exprs {
|
|
|
|
|
2021-06-01 20:47:46 +01:00
|
|
|
Fn::Fn(SereneContext &ctx, reader::LocationRange &loc, List &args, Ast body)
|
2021-10-17 14:33:16 +01:00
|
|
|
: Expression(loc), args(args), body(std::move(body)) {
|
2021-06-01 20:47:46 +01:00
|
|
|
this->setName(
|
2021-10-13 11:27:54 +01:00
|
|
|
llvm::formatv("___fn___{0}", ctx.getCurrentNS().nextFnCounter()));
|
2021-06-01 20:47:46 +01:00
|
|
|
};
|
|
|
|
|
2021-04-24 14:39:43 +01:00
|
|
|
ExprType Fn::getType() const { return ExprType::Fn; };
|
|
|
|
|
|
|
|
std::string Fn::toString() const {
|
|
|
|
return llvm::formatv("<Fn {0} {1} to {2}>",
|
|
|
|
this->name.empty() ? "Anonymous" : this->name,
|
|
|
|
this->args.toString(),
|
|
|
|
this->body.empty() ? "<>" : astToString(&this->body));
|
|
|
|
}
|
|
|
|
|
2021-09-27 13:05:15 +01:00
|
|
|
MaybeNode Fn::analyze(SereneContext &ctx) {
|
|
|
|
UNUSED(ctx);
|
|
|
|
return EmptyNode;
|
|
|
|
};
|
2021-04-24 14:39:43 +01:00
|
|
|
|
|
|
|
bool Fn::classof(const Expression *e) { return e->getType() == ExprType::Fn; };
|
|
|
|
|
2021-10-17 14:33:16 +01:00
|
|
|
void Fn::setName(std::string n) { this->name = std::move(n); };
|
2021-06-01 20:47:46 +01:00
|
|
|
|
2021-04-25 23:05:21 +01:00
|
|
|
MaybeNode Fn::make(SereneContext &ctx, List *list) {
|
2021-04-24 14:39:43 +01:00
|
|
|
// TODO: Add support for docstring as the 3rd argument (4th element)
|
|
|
|
if (list->count() < 2) {
|
2021-10-24 12:34:20 +01:00
|
|
|
return makeErrorful<Node>(list->elements[0]->location, errors::FnNoArgsList,
|
2021-05-06 19:17:57 +01:00
|
|
|
"The argument list is mandatory.");
|
2021-04-24 14:39:43 +01:00
|
|
|
}
|
|
|
|
|
2021-04-24 18:04:04 +01:00
|
|
|
Symbol *fnSym = llvm::dyn_cast<Symbol>(list->elements[0].get());
|
2021-08-07 17:41:19 +01:00
|
|
|
|
|
|
|
// TODO: Replace this assert with a runtime check
|
2021-04-24 18:04:04 +01:00
|
|
|
assert((fnSym && fnSym->name == "fn") &&
|
|
|
|
"The first element of the list should be a 'fn'.");
|
|
|
|
|
2021-04-24 14:39:43 +01:00
|
|
|
List *args = llvm::dyn_cast<List>(list->elements[1].get());
|
|
|
|
|
2021-10-17 14:33:16 +01:00
|
|
|
if (args == nullptr) {
|
2021-04-24 14:39:43 +01:00
|
|
|
std::string msg =
|
|
|
|
llvm::formatv("Arguments of a function has to be a list, got '{0}'",
|
|
|
|
stringifyExprType(list->elements[1]->getType()));
|
2021-08-07 17:41:19 +01:00
|
|
|
|
2021-05-06 19:17:57 +01:00
|
|
|
return makeErrorful<Node>(list->elements[1]->location,
|
2021-10-24 12:34:20 +01:00
|
|
|
errors::FnArgsMustBeList, msg);
|
2021-04-24 14:39:43 +01:00
|
|
|
}
|
|
|
|
|
2021-04-25 23:07:08 +01:00
|
|
|
Ast body;
|
2021-04-24 14:39:43 +01:00
|
|
|
|
2021-08-07 17:41:19 +01:00
|
|
|
// If there is a body for this function analyze the body and set
|
|
|
|
// the retuned ast as the final body
|
2021-04-24 14:39:43 +01:00
|
|
|
if (list->count() > 2) {
|
2021-06-13 22:58:46 +01:00
|
|
|
body = std::vector<Node>(list->begin() + 2, list->end());
|
2021-04-24 20:18:33 +01:00
|
|
|
auto maybeAst = reader::analyze(ctx, body);
|
|
|
|
|
|
|
|
if (!maybeAst) {
|
2021-05-06 19:17:57 +01:00
|
|
|
return MaybeNode::error(std::move(maybeAst.getError()));
|
2021-04-24 20:18:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
body = maybeAst.getValue();
|
2021-04-24 14:39:43 +01:00
|
|
|
}
|
|
|
|
|
2021-06-01 20:47:46 +01:00
|
|
|
return makeSuccessfulNode<Fn>(ctx, list->location, *args, body);
|
2021-04-24 14:39:43 +01:00
|
|
|
};
|
2021-06-23 20:34:57 +01:00
|
|
|
|
2021-08-15 12:06:56 +01:00
|
|
|
void Fn::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) {
|
2021-09-23 19:24:51 +01:00
|
|
|
auto loc = slir::toMLIRLocation(ns, location.start);
|
|
|
|
auto &ctx = ns.getContext();
|
2021-08-15 12:06:56 +01:00
|
|
|
|
2021-06-23 20:34:57 +01:00
|
|
|
mlir::OpBuilder builder(&ctx.mlirContext);
|
|
|
|
|
2021-06-25 21:47:24 +01:00
|
|
|
// llvm::SmallVector<mlir::Type, 4> arg_types;
|
|
|
|
llvm::SmallVector<mlir::NamedAttribute, 4> arguments;
|
2021-06-23 20:34:57 +01:00
|
|
|
// at the moment we only support integers
|
2021-06-25 21:47:24 +01:00
|
|
|
for (auto &arg : args) {
|
|
|
|
auto *argSym = llvm::dyn_cast<Symbol>(arg.get());
|
|
|
|
|
2021-10-17 14:33:16 +01:00
|
|
|
if (argSym == nullptr) {
|
2021-08-15 12:06:56 +01:00
|
|
|
m->emitError(llvm::formatv(
|
2021-06-25 21:47:24 +01:00
|
|
|
"Arguments of a function have to be symbols. Fn: '{0}'", name));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
arguments.push_back(builder.getNamedAttr(
|
|
|
|
argSym->name, mlir::TypeAttr::get(builder.getI64Type())));
|
2021-06-23 20:34:57 +01:00
|
|
|
}
|
|
|
|
|
2021-06-25 21:47:24 +01:00
|
|
|
auto fn = builder.create<slir::FnOp>(
|
|
|
|
loc, builder.getI64Type(), name,
|
|
|
|
mlir::DictionaryAttr::get(builder.getContext(), arguments),
|
|
|
|
builder.getStringAttr("public"));
|
2021-06-23 20:34:57 +01:00
|
|
|
|
|
|
|
if (!fn) {
|
2021-08-15 12:06:56 +01:00
|
|
|
m.emitError(llvm::formatv("Can't create the function '{0}'", name));
|
2021-09-23 19:24:51 +01:00
|
|
|
return;
|
2021-06-23 20:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto &body = fn.body();
|
2021-09-23 19:24:51 +01:00
|
|
|
auto *entryBlock = new mlir::Block();
|
|
|
|
|
2021-06-23 20:34:57 +01:00
|
|
|
body.push_back(entryBlock);
|
2021-09-23 19:24:51 +01:00
|
|
|
|
2021-06-23 20:34:57 +01:00
|
|
|
builder.setInsertionPointToStart(entryBlock);
|
|
|
|
auto retVal = builder.create<slir::ValueOp>(loc, 0).getResult();
|
|
|
|
|
2021-09-23 19:24:51 +01:00
|
|
|
slir::ReturnOp returnOp = builder.create<slir::ReturnOp>(loc, retVal);
|
2021-06-23 20:34:57 +01:00
|
|
|
|
|
|
|
if (!returnOp) {
|
2021-08-15 12:06:56 +01:00
|
|
|
m.emitError(
|
2021-06-23 20:34:57 +01:00
|
|
|
llvm::formatv("Can't create the return value of function '{0}'", name));
|
2021-09-23 19:24:51 +01:00
|
|
|
fn.erase();
|
2021-06-23 20:34:57 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-09-23 19:24:51 +01:00
|
|
|
|
2021-08-15 12:06:56 +01:00
|
|
|
m.push_back(fn);
|
2021-06-23 20:34:57 +01:00
|
|
|
};
|
2021-04-24 14:39:43 +01:00
|
|
|
} // namespace exprs
|
|
|
|
} // namespace serene
|