/* * Serene Programming Language * * Copyright (c) 2019-2022 Sameer Rahmani * * 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. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "serene/exprs/call.h" #include "serene/errors.h" #include "serene/exprs/def.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.h" #include "serene/exprs/symbol.h" #include "serene/namespace.h" #include "serene/utils.h" #include #include #include namespace serene { namespace exprs { ExprType Call::getType() const { return ExprType::Call; }; std::string Call::toString() const { return llvm::formatv("", this->target->toString(), astToString(&this->params)); } MaybeNode Call::analyze(semantics::AnalysisState &state) { UNUSED(state); return EmptyNode; }; bool Call::classof(const Expression *e) { return e->getType() == ExprType::Call; }; MaybeNode Call::make(semantics::AnalysisState &state, List *list) { auto &ctx = state.ns.getContext(); // TODO: replace this with a runtime check 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(state); if (!maybeFirst) { // There's something wrong with the first element. Return the error return maybeFirst; } Node &first = *maybeFirst; // No rewrite is needed for the first element if (!first) { first = list->elements[0]; } Node targetNode; Ast rawParams; if (list->count() > 1) { rawParams = list->from(1); } // We need to create the Call node based on the type of the first // element after it being analyzed. switch (first->getType()) { // In case of a Symbol, We should look it up in the current scope and // if it resolves to a value. Then we have to make sure that the // return value is callable. case ExprType::Symbol: { auto *sym = llvm::dyn_cast(first.get()); if (sym == nullptr) { llvm_unreachable("Couldn't case to Symbol while the type is symbol!"); } auto maybeResult = state.env.lookup(sym->name); if (!maybeResult.hasValue()) { std::string msg = llvm::formatv("Can't resolve the symbol '{0}'", sym->name); return errors::makeError(ctx, errors::CantResolveSymbol, sym->location, msg); } targetNode = std::move(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 // the typechecker to check case ExprType::Call: // If the first element was a function, then just use it as the target // of the call. It would be like `((fn (x) x) 4)` case ExprType::Fn: { targetNode = first; break; } // Otherwise we don't know how to call the first element. default: { std::string msg = llvm::formatv("Don't know how to call a '{0}'", stringifyExprType(first->getType())); return errors::makeError(ctx, errors::DontKnowHowToCallNode, first->location, msg); } }; auto analyzedParams = semantics::analyze(state, rawParams); if (!analyzedParams) { return analyzedParams.takeError(); } return makeSuccessfulNode(list->location, targetNode, *analyzedParams); }; } // namespace exprs } // namespace serene