aboutsummaryrefslogtreecommitdiffstats
path: root/ast.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ast.cpp')
-rw-r--r--ast.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/ast.cpp b/ast.cpp
new file mode 100644
index 0000000..d23ff0d
--- /dev/null
+++ b/ast.cpp
@@ -0,0 +1,228 @@
+/**
+ * lisp-compiler: Compiles LISP using LLVM.
+ * Copyright (C) 2022 Clyne Sullivan
+ *
+ * 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, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * @file ast.cpp
+ * @brief Abstract Syntax Tree (AST) implementation.
+ */
+
+#include "ast.hpp"
+#include "state.hpp"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Type.h"
+
+#include <algorithm>
+#include <any>
+#include <cctype>
+#include <cstdio>
+#include <deque>
+#include <iostream>
+#include <map>
+#include <optional>
+#include <string>
+#include <typeinfo>
+#include <variant>
+#include <vector>
+
+AST::Value AST::Identifier::codegen(CompilerState& state)
+{
+ if (state.namedValues.contains(name))
+ return state.namedValues[name];
+ else
+ return nullptr;
+}
+
+AST::Value AST::Literal::codegen(CompilerState& state)
+{
+ if (type == AST::Literal::Type::Number) {
+ if (std::holds_alternative<int>(value))
+ return llvm::ConstantInt::get(state.context, llvm::APInt(sizeof(int) * 8, std::get<int>(value)));
+ else
+ return llvm::ConstantFP::get(state.context, llvm::APFloat(std::get<double>(value)));
+ } else {
+ return nullptr;
+ }
+}
+
+AST::Value AST::ProcedureCall::codegen(CompilerState& state)
+{
+ if (auto id = dynamic_cast<AST::Identifier *>(callee); id) {
+ if (state.namedValues.contains(id->name)) {
+ auto ptrToFuncPtr = state.namedValues[id->name];
+ auto funcPtr = state.builder.CreateLoad(
+ ptrToFuncPtr->getType()->getContainedType(0),
+ ptrToFuncPtr);
+ auto funcType = (llvm::FunctionType *)funcPtr->getType()->getContainedType(0);
+ return state.builder.CreateCall(funcType, funcPtr, llvm::None, "calltmp");
+ } else {
+ std::vector<llvm::Value *> args;
+ std::vector<llvm::Type *> argtypes;
+
+ for (auto& a : operands) {
+ args.push_back(a->codegen(state));
+ argtypes.push_back(args.back()->getType());
+ }
+
+
+ auto func = state.module.getOrInsertFunction(id->name,
+ llvm::FunctionType::get(
+ llvm::Type::getVoidTy(state.context),
+ argtypes,
+ false));
+ return state.builder.CreateCall(func, args);
+ }
+
+ // work off of id's name
+ // builtin?
+ // named value? (i.e. is defined)
+ return nullptr;
+ } else if (auto v = callee->codegen(state); v) {
+ // v needs to be a callable procedure
+ //std::vector<Node *> operands;
+ return nullptr;
+ } else {
+ return nullptr;
+ }
+}
+
+AST::Value AST::LambdaExpression::codegen(CompilerState& state)
+{
+ std::vector<llvm::Type *> args;
+ std::vector<std::string> argnames;
+
+ for (auto& op : operands) {
+ args.push_back(llvm::Type::getDoubleTy(state.context));
+ argnames.push_back(op->name);
+ }
+
+ auto ftype = llvm::FunctionType::get(
+ llvm::Type::getDoubleTy(state.context), args, false);
+ auto func = llvm::Function::Create(
+ ftype, llvm::Function::ExternalLinkage, "lambda", &state.module);
+
+ auto n = argnames.cbegin();
+ for (auto& a : func->args()) {
+ a.setName(*n);
+ state.namedValues[*n] = &a;
+ ++n;
+ }
+
+ auto block = llvm::BasicBlock::Create(state.context, "entry", func);
+
+ auto ip = state.builder.saveIP();
+ state.builder.SetInsertPoint(block);
+ ++state.scope;
+
+ llvm::Value *ret;
+ for (auto& b : body)
+ ret = b->codegen(state);
+
+ if (ret)
+ state.builder.CreateRet(ret);
+ else
+ state.builder.CreateRetVoid();
+
+ --state.scope;
+ state.builder.restoreIP(ip);
+
+ for (auto& a : argnames)
+ state.namedValues.erase(a);
+
+ return func;
+}
+
+AST::Value AST::Conditional::codegen(CompilerState& state)
+{
+ auto cval = state.builder.CreateFCmpONE(
+ cond->codegen(state),
+ llvm::ConstantFP::get(state.context, llvm::APFloat(0.0)),
+ "ifcond");
+
+ auto func = state.builder.GetInsertBlock()->getParent();
+
+ auto bthen = llvm::BasicBlock::Create(state.context, "then", func);
+ auto belse = llvm::BasicBlock::Create(state.context, "else", func);
+ auto bcont = llvm::BasicBlock::Create(state.context, "cont", func);
+ state.builder.CreateCondBr(cval, bthen, belse);
+
+ state.builder.SetInsertPoint(bthen);
+ auto vthen = iftrue->codegen(state);
+ if (!vthen || vthen->getType() != llvm::Type::getDoubleTy(state.context))
+ vthen = llvm::ConstantFP::get(state.context, llvm::APFloat(0.0));
+ state.builder.CreateBr(bcont);
+
+ state.builder.SetInsertPoint(belse);
+ auto velse = iffalse->codegen(state);
+ if (!velse || velse->getType() != llvm::Type::getDoubleTy(state.context))
+ velse = llvm::ConstantFP::get(state.context, llvm::APFloat(0.0));
+ state.builder.CreateBr(bcont);
+
+ state.builder.SetInsertPoint(bcont);
+ auto PN = state.builder.CreatePHI(
+ llvm::Type::getDoubleTy(state.context), 2, "iftmp");
+
+ PN->addIncoming(vthen, bthen);
+ PN->addIncoming(velse, belse);
+ return PN;
+}
+
+AST::Value AST::Definition::codegen(CompilerState& state)
+{
+ if (!state.namedValues.contains(ident->name)) {
+ if (state.scope == 0) {
+ auto val = (llvm::Constant *)value->codegen(state);
+
+ state.module.getOrInsertGlobal(ident->name, val->getType());
+
+ auto var = state.module.getNamedGlobal(ident->name);
+ var->setLinkage(llvm::Function::ExternalLinkage);
+ var->setInitializer(val);
+ state.namedValues[ident->name] = var;
+ return var;
+ } else {
+ auto alloc = state.builder.CreateAlloca(
+ llvm::Type::getDoubleTy(state.context),
+ nullptr,
+ ident->name);
+ state.builder.CreateStore(value->codegen(state), alloc);
+ state.namedValues[ident->name] = alloc;
+ return alloc;
+ }
+ } else {
+ return nullptr;
+ }
+}
+
+AST::Value AST::Assignment::codegen(CompilerState& state)
+{
+ if (state.scope > 0) {
+ if (state.namedValues.contains(ident->name)) {
+ return state.builder.CreateStore(value->codegen(state), state.namedValues[ident->name]);
+ }
+ }
+
+ return nullptr;
+}
+
+