Update the serene executable to use llvm::cl and spit out the AST

This commit is contained in:
Sameer Rahmani 2021-03-22 19:53:10 +00:00
parent cd0989d060
commit 04a50eb65b
14 changed files with 217 additions and 44 deletions

View File

@ -7,6 +7,7 @@ project(Serene
LANGUAGES CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
# Only do these if this is the main project, and not if it is included through add_subdirectory
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
@ -34,6 +35,8 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(MemoryCheckCommand "valgrind")
add_compile_options(-fno-rtti)
configure_file(${INCLUDE_DIR}/config.h.in config.h)
# Let's nicely support folders in IDEs
@ -93,4 +96,5 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
add_subdirectory(tests)
endif()
endif()

View File

@ -24,6 +24,7 @@
#include "serene/serene.hpp"
#include "serene/compiler.hpp"
#include "serene/reader.hpp"
#include <iostream>
#include <llvm/Support/CommandLine.h>
@ -33,27 +34,31 @@ using namespace serene;
namespace cl = llvm::cl;
namespace {
enum Action { None, DumpAST }
enum Action { None, DumpAST };
}
static cl::opt<std::string> inputFile(cl::Positional,
cl::desc("The Serene file to compile"),
cl::init("-"),
cl::value_desc("filename"));
static cl::opt<enum Action>
emitAction("emit", cl::desc("Select what to dump."),
cl::values(clEnumValN(DumpAST, "ast", "Output the AST only")));
int main(int argc, char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "Serene compiler \n");
switch (emitAction) {
case Action::DumpAST:
Reader r = Reader(input);
r->dump();
case Action::DumpAST: {
FileReader *r = new FileReader(inputFile);
r->dumpAST();
return 0;
}
default: {
llvm::errs() << "No action specified. TODO: Print out help here";
}
}
string input_file(argv[1]);
Compiler c;
c.compile(input_file);
return 0;
return 1;
}

View File

@ -0,0 +1 @@
(println asd)

52
include/serene/error.hpp Normal file
View File

@ -0,0 +1,52 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef ERROR_H
#define ERROR_H
#include "serene/compiler.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/state.hpp"
#include <string>
namespace serene {
class Error : public AExpr {
const std::string msg;
public:
Error(const std::string &msg) : msg(msg) {}
virtual ~Error();
const std::string &message() const;
ExprId id() const override { return error; }
std::string string_repr() const override;
std::string dumpAST() const override;
llvm::Value *codegen(Compiler &compiler, State &state) override;
};
} // namespace serene
#endif

View File

@ -39,7 +39,8 @@
namespace serene {
enum ExprId : unsigned char { aexpr = 0, symbol, list, def };
// TODO: Rename this enum and move it to a namespace
enum ExprId : unsigned char { aexpr = 0, symbol, list, def, error };
class AExpr {
public:
@ -48,6 +49,7 @@ public:
virtual ExprId id() const = 0;
virtual std::string string_repr() const = 0;
virtual llvm::Value *codegen(Compiler &compiler, State &state) = 0;
virtual std::string dumpAST() const = 0;
};
using ast_node = std::shared_ptr<AExpr>;

View File

@ -38,6 +38,7 @@ class List : public AExpr {
public:
ExprId id() const override { return list; }
std::string dumpAST() const override;
std::string string_repr() const override;
size_t length() const;

View File

@ -72,11 +72,33 @@ private:
ast_node read_expr();
public:
Reader(const std::string &);
Reader() : input_stream(""){};
Reader(const std::string);
void setInput(const std::string);
ast_tree &read();
// Dumps the AST data to stdout
void dumpAST();
~Reader();
};
class FileReader {
std::string file;
Reader *reader;
public:
FileReader(const std::string file_name)
: file(file_name), reader(new Reader()) {}
// Dumps the AST data to stdout
void dumpAST();
ast_tree &read();
~FileReader();
};
} // namespace serene
#endif

View File

@ -51,6 +51,7 @@ public:
ExprId id() const override { return def; }
Def(serene::Symbol *symbol_, AExpr *value_);
std::string dumpAST() const override;
std::string string_repr() const override;
llvm::Value *codegen(Compiler &compiler, State &state) override;
static ast_node make(Compiler &compiler, State &state, const List *args);

View File

@ -43,6 +43,7 @@ public:
ExprId id() const override { return symbol; }
std::string string_repr() const override;
std::string dumpAST() const override;
llvm::Value *codegen(Compiler &compiler, State &state) override;
};

49
src/error.cpp Normal file
View File

@ -0,0 +1,49 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/error.hpp"
#include "serene/compiler.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/state.hpp"
#include <assert.h>
#include <fmt/core.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Type.h>
#include <string>
using namespace std;
using namespace llvm;
namespace serene {
string Error::string_repr() const { return fmt::format("Error: {}", msg); }
string Error::dumpAST() const { return fmt::format("<Error: {}>", this->msg); }
Value *Error::codegen(Compiler &compiler, State &state) { return nullptr; }
Error::~Error() { EXPR_LOG("Destroying Error"); }
} // namespace serene

View File

@ -60,35 +60,17 @@ std::string List::string_repr() const {
return fmt::format("({})", s);
}
std::string List::dumpAST() const {
std::string s;
for (auto &n : nodes_) {
s = fmt::format("{} {}", s, n->dumpAST());
}
return fmt::format("<List: {}>", s);
}
inline size_t List::length() const { return nodes_.size(); }
Value *List::codegen(Compiler &compiler, State &state) {
if (length() == 0) {
compiler.log_error("Can't eveluate empty list.");
return nullptr;
}
auto def_ptr = at(0).value_or(nullptr);
auto name_ptr = at(1).value_or(nullptr);
auto body_ptr = at(2).value_or(nullptr);
if (def_ptr && def_ptr->id() == symbol &&
static_cast<Symbol *>(def_ptr.get())->name() == "def") {
if (!name_ptr && def_ptr->id() != symbol) {
return compiler.log_error("First argument of 'def' has to be a symbol.");
}
if (!body_ptr) {
return compiler.log_error("'def' needs 3 arguments, two has been given.");
}
special_forms::Def def(static_cast<Symbol *>(name_ptr.get()),
body_ptr.get());
return def.codegen(compiler, state);
}
EXPR_LOG("Not implemented in list.");
return nullptr;
}
Value *List::codegen(Compiler &compiler, State &state) { return nullptr; }
} // namespace serene

View File

@ -23,9 +23,11 @@
*/
#include "serene/reader.hpp"
#include "serene/error.hpp"
#include "serene/list.hpp"
#include "serene/symbol.hpp"
#include <assert.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
@ -33,7 +35,9 @@
using namespace std;
namespace serene {
Reader::Reader(const string &input) {
Reader::Reader(const string input) { this->setInput(input); };
void Reader::setInput(const string input) {
input_stream.write(input.c_str(), input.size());
};
@ -153,5 +157,48 @@ ast_tree &Reader::read() {
}
return this->ast;
};
}
void Reader::dumpAST() {
ast_tree &ast = this->read();
std::string result = "";
for (auto &node : ast) {
result = fmt::format("{0} {1}", result, node->dumpAST());
}
}
ast_tree &FileReader::read() {
std::string buffer;
std::ifstream f(file.c_str());
if (f) {
f.seekg(0, std::ios::end);
buffer.resize(f.tellg());
f.seekg(0);
f.read(buffer.data(), buffer.size());
f.close();
reader->setInput(buffer);
return reader->read();
}
throw ReadError((char *)fmt::format("Can't find file '{}'", file).c_str());
}
void FileReader::dumpAST() {
ast_tree &ast = this->read();
std::string result = "";
for (auto &node : ast) {
result = fmt::format("{0} {1}", result, node->dumpAST());
}
cout << result << endl;
}
FileReader::~FileReader() {
delete this->reader;
READER_LOG("Destroying the file reader");
}
} // namespace serene

View File

@ -72,6 +72,8 @@ string Def::string_repr() const {
return "Def";
}
string Def::dumpAST() const { return "<Def>"; }
Value *Def::codegen(Compiler &compiler, State &state) {
state.set_in_current_ns_root_scope(m_sym->name(),
m_value->codegen(compiler, state));

View File

@ -41,6 +41,10 @@ namespace serene {
string Symbol::string_repr() const { return name_; }
string Symbol::dumpAST() const {
return fmt::format("<Symbol: {}>", this->name());
}
const string &Symbol::name() const { return name_; }
Symbol::Symbol(const string &name) : name_(name) {}