Finish the first implementation of the compiler level list

This commit is contained in:
Sameer Rahmani 2020-07-23 17:13:16 +01:00
parent d55b4a27f5
commit 8e90ea9813
14 changed files with 281 additions and 174 deletions

View File

@ -10,90 +10,87 @@ 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)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
## Settings -----------------------------------------
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
set(CMAKE_CXX_CLANG_TIDY clang-tidy-10)
# Let's ensure -std=c++xx instead of -std=g++xx
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -g -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG
"${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
set(CMAKE_CXX_CLANG_TIDY clang-tidy-10)
# Let's ensure -std=c++xx instead of -std=g++xx
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -g -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG
"${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(MemoryCheckCommand "valgrind")
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(MemoryCheckCommand "valgrind")
# Let's nicely support folders in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
configure_file(${INCLUDE_DIR}/config.h.in config.h)
# Testing only available if this is the main app
# Note this needs to be done in the main CMakeLists
# since it calls enable_testing, which must be in the
# main CMakeLists.
include(CTest)
# Let's nicely support folders in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Docs only available if this is the main app
find_package(Doxygen)
if(Doxygen_FOUND)
add_subdirectory(docs)
else()
message(STATUS "Doxygen not found, not building docs")
endif()
endif()
## Options ------------------------------------------
option(ENABLE_LOG "Enable logging" OFF)
option(ENABLE_EXPR_LOG "Enable AExpr logging" OFF)
option(ENABLE_READER_LOG "Enable reader logging" OFF)
include(cotire)
include(FetchContent)
# Testing only available if this is the main app
# Note this needs to be done in the main CMakeLists
# since it calls enable_testing, which must be in the
# main CMakeLists.
include(CTest)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs support core irreader)
# Formatting library
FetchContent_Declare(
fmtlib
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 7.0.1
)
FetchContent_MakeAvailable(fmtlib)
# Docs only available if this is the main app
find_package(Doxygen)
if(Doxygen_FOUND)
add_subdirectory(docs)
else()
message(STATUS "Doxygen not found, not building docs")
endif()
# The compiled library code is here
add_subdirectory(src)
include(cotire)
include(FetchContent)
# The executable code is here
add_subdirectory(bin)
find_package(LLVM REQUIRED CONFIG)
# Testing only available if this is the main app
# Emergency override SERENE_CMAKE_BUILD_TESTING provided as well
if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR SERENE_CMAKE_BUILD_TESTING) AND BUILD_TESTING)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs support core irreader)
# Formatting library
FetchContent_Declare(
fmtlib
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 7.0.1
)
FetchContent_MakeAvailable(fmtlib)
# The compiled library code is here
add_subdirectory(src)
# The executable code is here
add_subdirectory(bin)
# Testing only available if this is the main app
# Emergency override SERENE_CMAKE_BUILD_TESTING provided as well
if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR SERENE_CMAKE_BUILD_TESTING) AND BUILD_TESTING)
add_subdirectory(tests)
endif()
endif()
#configure_file(${INCLUDE_DIR}/config.h.in config.h)
# target_link_libraries(serene ${llvm_libs})
# target_include_directories(serene SYSTEM PRIVATE $ENV{INCLUDE})
# target_include_directories(serene PRIVATE ${INCLUDE_DIR})
# target_include_directories(serene PUBLIC ${PROJECT_BINARY_DIR})
# install(TARGETS serene DESTINATION bin)
# install(FILES "${PROJECT_BINARY_DIR}/serene/config.h"
# DESTINATION include
# )

View File

@ -7,11 +7,10 @@ target_link_libraries(serene PRIVATE
fmt::fmt
)
target_include_directories(serene SYSTEM PRIVATE $ENV{INCLUDE})
target_include_directories(serene PRIVATE ${INCLUDE_DIR})
target_include_directories(serene PUBLIC ${PROJECT_BINARY_DIR})
install(TARGETS serene DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/serene/config.h"
DESTINATION include
)
install(FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)
cotire(serene)

View File

@ -36,16 +36,10 @@ int main(int argc, char *argv[]) {
char *input_file = argv[1];
Reader *r = new Reader(input_file);
ast_tree &ast = r->read();
cout << "Size: " << ast.size() << endl;
cout << ast.at(2)->string_repr() << endl;
// for(const ast_node& x : ast) {
// cout << x->string_repr() << " >> ";
// }
for(const ast_node& x : ast) {
cout << x->string_repr() << " ";
}
delete r;
cout << "\nEND<<" << endl;
return 0;
}

44
builder
View File

@ -13,24 +13,32 @@ BUILD_DIR=$ROOT_DIR/build
scanbuild=scan-build-10
function pushed_build() {
pushd $BUILD_DIR > /dev/null
}
function popd_build() {
popd > /dev/null
}
function compile() {
pushd $BUILD_DIR
pushed_build
ninja
popd
popd_build
}
function build() {
pushd $BUILD_DIR
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug $ROOT_DIR
pushed_build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug "$@" $ROOT_DIR
ninja -j `nproc`
popd
popd_build
}
function build-release() {
pushd $BUILD_DIR
pushed_build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release $ROOT_DIR
ninja -j `nproc`
popd
popd_build
}
function clean() {
@ -38,21 +46,21 @@ function clean() {
}
function run() {
pushd $BUILD_DIR
pushed_build
$BUILD_DIR/bin/serene "$@"
popd
popd_build
}
function memcheck() {
pushd $BUILD_DIR
pushed_build
ctest -T memcheck
popd
popd_build
}
function tests() {
pushd $BUILD_DIR
pushed_build
ctest
popd
popd_build
}
@ -67,29 +75,27 @@ case "$command" in
"build")
clean
mkdir -p $BUILD_DIR
build
build "${@:2}"
;;
"build-release")
clean
mkdir -p $BUILD_DIR
build
build "${@:2}"
;;
"compile")
compile
;;
"run")
echo "##############"
echo "${@:2}"
run "${@:2}"
;;
"scan-build")
clean
mkdir -p $BUILD_DIR
pushd $BUILD_DIR
pushed_build
exec $scanbuild cmake $ROOT_DIR
exec $scanbuild scan-build make -j 4
popd
popd_build
;;
"memcheck")
memcheck

View File

@ -1,3 +1,11 @@
#ifndef CONFIG_H
#define CONFIG_H
// the configured options and settings for Tutorial
#define SERENE_VERSION_MAJOR @Serene_VERSION_MAJOR@
#define SERENE_VERSION_MINOR @Serene_VERSION_MINOR@
#cmakedefine ENABLE_READER_LOG
#cmakedefine ENABLE_EXPR_LOG
#cmakedefine ENABLE_LOG
#endif

View File

@ -26,8 +26,15 @@
#define EXPR_H
#include <string>
#include "serene/logger.hpp"
#include "serene/llvm/IR/Value.h"
#if defined(ENABLE_LOG) || defined(ENABLE_EXPR_LOG)
#define EXPR_LOG(...) __LOG("EXPR", __VA_ARGS__);
#else
#define EXPR_LOG(...);
#endif
namespace serene {
class AExpr {
public:

View File

@ -34,29 +34,35 @@ namespace serene {
class ListNode {
public:
ast_node data;
std::shared_ptr<ListNode> next;
std::shared_ptr<ListNode> prev;
ListNode(ast_node node_data) : data{move(node_data)},
ListNode* next;
ListNode* prev;
ListNode(ast_node node_data) : data{std::move(node_data)},
next{nullptr},
prev{nullptr} {};
};
class List: public AExpr {
public:
std::unique_ptr<ListNode> head;
std::unique_ptr<ListNode> tail;
ListNode* head;
ListNode* tail;
std::size_t len;
List(): head{nullptr}, tail{nullptr}, len{0} {};
List(const List &list);
List(List &&list);
List(List &&list) noexcept;
List& operator=(const List& other);
List& operator=(List&& other);
std::string string_repr();
std::size_t length();
void cons(ast_node f);
void add_tail(ast_node t);
void append(ast_node t);
AExpr &first();
List &rest();
void cleanup();
virtual ~List();

40
include/serene/logger.hpp Normal file
View File

@ -0,0 +1,40 @@
/**
* 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 LOGGER_H
#define LOGGER_H
#include <fmt/core.h>
#include "config.h"
// DO NOT USE this macro directly. USE module specific macro.
// Checkout `reader.cpp` for example.
#define __LOG(M, ...) fmt::print("[{}] <{}:{}> in '{}': {}\n", \
M, \
__FILE__, \
__LINE__, \
__func__, \
fmt::format(__VA_ARGS__));
#endif

View File

@ -31,13 +31,17 @@
#include <vector>
#include <stdexcept>
#include <fmt/core.h>
#include "serene/logger.hpp"
#include "serene/expr.hpp"
#include "serene/list.hpp"
#include "serene/symbol.hpp"
#include "serene/serene.hpp"
#define ENABLE_READER_LOG true
#define READER_LOG(...) if(ENABLE_READER_LOG) { fmt::print(__VA_ARGS__); }
#if defined(ENABLE_READER_LOG) || defined(ENABLE_LOG)
#define READER_LOG(...) __LOG("READER", __VA_ARGS__);
#else
#define READER_LOG(...);
#endif
namespace serene {

View File

@ -29,8 +29,5 @@
// and the fn signature right.
#define UNUSED(x) (void)(x)
namespace serene {
}
namespace serene {}
#endif

View File

@ -16,6 +16,7 @@ add_library(lserene
# We need this directory, and users of our library will need it too
target_include_directories(lserene PUBLIC "${INCLUDE_DIR}")
target_compile_features(lserene PUBLIC cxx_std_20)
target_include_directories(lserene PUBLIC ${PROJECT_BINARY_DIR})
# This depends on (header only) boost
target_link_libraries(lserene ${llvm_libs} fmt::fmt)

View File

@ -31,65 +31,104 @@
using namespace std;
namespace serene {
List::List(const List &list) {
ListNode *root = list.head;
ListNode *new_head{nullptr};
ListNode *prev_new_head{nullptr};
while(root) {
ListNode *temp = new ListNode(unique_ptr<AExpr>(root->data.get()));
if(new_head == nullptr) {
new_head = temp;
prev_new_head = new_head;
} else {
prev_new_head->next = temp;
prev_new_head = prev_new_head->next;
}
root = root->next;
}
head = new_head;
};
List::List(List &&list) noexcept: head(list.head),
tail(list.tail),
len(std::exchange(list.len, 0)) {
list.head = nullptr;
list.tail = nullptr;
};
List& List::operator=(const List& list) {
ListNode *root = list.head;
ListNode *new_head{nullptr};
ListNode *prev_new_head{nullptr};
while(root) {
ListNode *temp = new ListNode(unique_ptr<AExpr>(root->data.get()));
if(new_head == nullptr) {
new_head = temp;
prev_new_head = new_head;
} else {
prev_new_head->next = temp;
prev_new_head = prev_new_head->next;
}
root = root->next;
}
head = new_head;
return *this;
};
List& List::operator=(List&& list) {
head = list.head;
tail = list.tail;
len = std::exchange(list.len, 0);
list.head = nullptr;
list.tail = nullptr;
return *this;
};
void List::cons(ast_node f) {
auto temp{std::make_unique<ListNode>(move(f))};
ListNode *temp = new ListNode(move(f));
if(head) {
temp->next = move(head);
head->prev = move(temp);
head = move(temp);
temp->next = head;
head->prev = temp;
head = temp;
}
else {
head = move(temp);
head = temp;
}
len++;
}
List::List(const List &list) {
ListNode *root = list.head.get();
unique_ptr<ListNode> new_head{nullptr};
ListNode *pnew_head{nullptr};
while(root) {
auto temp{std::make_unique<ListNode>(unique_ptr<AExpr>(root->data.get()))};
if(new_head == nullptr) {
new_head = move(temp);
pnew_head = new_head.get();
} else {
pnew_head->next = move(temp);
pnew_head = pnew_head->next.get();
}
root = root->next.get();
}
head = move(new_head);
};
List::List(List &&list) {
head = move(list.head);
}
void List::add_tail(ast_node t) {
void List::append(ast_node t) {
// TODO: Should we do it here?
if(!t) {
return;
}
auto temp{std::make_unique<ListNode>(move(t))};
if(tail) {
temp->prev = move(tail);
tail->next = move(temp);
tail = move(temp);
ListNode *temp = new ListNode(move(t));
temp->prev = tail;
tail->next = temp;
tail = temp;
len++;
}
else {
if (head) {
head->next = move(temp);
tail->prev = move(head);
tail = move(temp);
ListNode *temp = new ListNode(move(t));
head->next = temp;
tail = temp;
tail->prev = head;
len++;
}
else {
@ -99,14 +138,22 @@ namespace serene {
}
string List::string_repr() {
fmt::print("sssssssssssssssssssssss {}\n", length());
// TODO: Fix this function to print out the list completely
if (head && head->data) {
return fmt::format("<List: '{}'>",
head->data->string_repr());
string s{"("};
for(ListNode* current = head, *next; current;) {
next = current->next;
s = s + current->data->string_repr();
current = next;
if (next) {
s = s + " ";
}
}
return fmt::format("{})", s);
}
else {
return "<List: empty>";
return "()";
}
};
@ -115,13 +162,16 @@ namespace serene {
}
void List::cleanup() {
while(head) {
head = move(head->next);
for (ListNode* current = head, *next; current;)
{
next = current->next;
delete current;
current = next;
}
};
List::~List() {
fmt::print("asdsadadsddddddddddddddddddddddddd\n");
EXPR_LOG("Destroying list");
cleanup();
};
}

View File

@ -38,7 +38,7 @@ namespace serene {
};
Reader::~Reader() {
fmt::print("DELETE reader\n");
READER_LOG("Destroying the reader");
}
char Reader::get_char(const bool skip_whitespace) {
@ -91,7 +91,7 @@ namespace serene {
bool empty = true;
char c = get_char(false);
READER_LOG("Read symbol\n");
READER_LOG("Reading symbol");
if(!this->is_valid_for_identifier(c)) {
// TODO: Replece this with a tranceback function or something to raise
@ -135,7 +135,7 @@ namespace serene {
default:
unget_char();
list->add_tail(read_expr());
list->append(read_expr());
}
} while(!list_terminated);
@ -146,7 +146,7 @@ namespace serene {
ast_node Reader::read_expr() {
char c = get_char(false);
READER_LOG("CHAR: {}\n", c);
READER_LOG("CHAR: {}", c);
unget_char();
@ -172,10 +172,8 @@ namespace serene {
this->ast.push_back(move(tmp));
}
c = get_char(true);
READER_LOG("11111 {}\n", c);
}
READER_LOG("333333333333333\n");
return this->ast;
};
}

View File

@ -32,10 +32,10 @@ using namespace std;
namespace serene {
string Symbol::string_repr() {
return fmt::format("<Symbol: '{}'>", name);
return name;
};
Symbol::~Symbol() {
fmt::print("symbol dest\n");
EXPR_LOG("Destroying symbol");
};
}