diff --git a/CMakeLists.txt b/CMakeLists.txt index b101d1e..fe0f8f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 -# ) diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 8e9b423..19fcfa5 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -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) diff --git a/bin/serene.cpp b/bin/serene.cpp index e7f6de1..6456e39 100644 --- a/bin/serene.cpp +++ b/bin/serene.cpp @@ -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; } diff --git a/builder b/builder index fa020a9..916b503 100755 --- a/builder +++ b/builder @@ -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 diff --git a/include/config.h.in b/include/config.h.in index ea2f561..e9b4bc3 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -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 diff --git a/include/serene/expr.hpp b/include/serene/expr.hpp index 7d93813..87b7544 100644 --- a/include/serene/expr.hpp +++ b/include/serene/expr.hpp @@ -26,8 +26,15 @@ #define EXPR_H #include +#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: diff --git a/include/serene/list.hpp b/include/serene/list.hpp index 5339328..eb415e0 100644 --- a/include/serene/list.hpp +++ b/include/serene/list.hpp @@ -34,29 +34,35 @@ namespace serene { class ListNode { public: ast_node data; - std::shared_ptr next; - std::shared_ptr 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 head; - std::unique_ptr 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(); diff --git a/include/serene/logger.hpp b/include/serene/logger.hpp new file mode 100644 index 0000000..8d676d7 --- /dev/null +++ b/include/serene/logger.hpp @@ -0,0 +1,40 @@ +/** + * Serene programming language. + * + * Copyright (c) 2020 Sameer Rahmani + * + * 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 +#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 diff --git a/include/serene/reader.hpp b/include/serene/reader.hpp index 0709fc2..e74957b 100644 --- a/include/serene/reader.hpp +++ b/include/serene/reader.hpp @@ -31,13 +31,17 @@ #include #include #include +#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 { diff --git a/include/serene/serene.hpp b/include/serene/serene.hpp index b94296e..794190f 100644 --- a/include/serene/serene.hpp +++ b/include/serene/serene.hpp @@ -29,8 +29,5 @@ // and the fn signature right. #define UNUSED(x) (void)(x) -namespace serene { - -} - +namespace serene {} #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a3978b..4760140 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/list.cpp b/src/list.cpp index 144952c..0e7cdbd 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -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(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(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(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 new_head{nullptr}; - ListNode *pnew_head{nullptr}; - - while(root) { - auto temp{std::make_unique(unique_ptr(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(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("", - 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 ""; + 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(); }; } diff --git a/src/reader.cpp b/src/reader.cpp index c4da381..12a4bbb 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -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; }; } diff --git a/src/symbol.cpp b/src/symbol.cpp index 66141c1..685e3a0 100644 --- a/src/symbol.cpp +++ b/src/symbol.cpp @@ -32,10 +32,10 @@ using namespace std; namespace serene { string Symbol::string_repr() { - return fmt::format("", name); + return name; }; Symbol::~Symbol() { - fmt::print("symbol dest\n"); + EXPR_LOG("Destroying symbol"); }; }