Add the build setup for the C++ implementation

This commit is contained in:
Sameer Rahmani 2020-07-10 18:06:26 +01:00
parent 72fb1f1a2c
commit 51b9f4a307
27 changed files with 4545 additions and 1222 deletions

13
.gitignore vendored
View File

@ -1,3 +1,14 @@
/target
*~
/build
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

93
CMakeLists.txt Normal file
View File

@ -0,0 +1,93 @@
cmake_minimum_required(VERSION 3.16)
# Project name and a few useful settings. Other commands can pick up the results
project(Serene
VERSION 0.1.0
DESCRIPTION "Serene language is a modern Lisp."
LANGUAGES CXX)
# 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)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
# set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
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} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG
"${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Let's nicely support folders in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# 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)
# 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()
include(cotire)
include(FetchContent)
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 5.3.0
# )
# 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()
#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
# )

454
Cargo.lock generated
View File

@ -1,454 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
dependencies = [
"memchr",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "clap"
version = "3.0.0-beta.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "860643c53f980f0d38a5e25dfab6c3c93b2cb3aa1fe192643d17a293c6c41936"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
"unicode-width",
"vec_map",
"yaml-rust",
]
[[package]]
name = "clap_derive"
version = "3.0.0-beta.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb51c9e75b94452505acd21d929323f5a5c6c4735a852adbd39ef5fb1b014f30"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe"
dependencies = [
"autocfg",
]
[[package]]
name = "inkwell"
version = "0.1.0"
source = "git+https://github.com/TheDan64/inkwell?branch=llvm10-0#84b9666c72ae9f286bfee559d13ac71ec8d1fce9"
dependencies = [
"either",
"inkwell_internals",
"libc",
"llvm-sys",
"once_cell",
"parking_lot",
"regex",
]
[[package]]
name = "inkwell_internals"
version = "0.2.0"
source = "git+https://github.com/TheDan64/inkwell?branch=llvm10-0#84b9666c72ae9f286bfee559d13ac71ec8d1fce9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
[[package]]
name = "linked-hash-map"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
[[package]]
name = "llvm-sys"
version = "100.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df29b4f2f4e8a5f7871ccad859aa17a171ba251da96bfd55224d53f48a96d2a2"
dependencies = [
"cc",
"lazy_static",
"libc",
"regex",
"semver",
]
[[package]]
name = "lock_api"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
dependencies = [
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "once_cell"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
[[package]]
name = "os_str_bytes"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06de47b848347d8c4c94219ad8ecd35eb90231704b067e67e6ae2e36ee023510"
[[package]]
name = "parking_lot"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
dependencies = [
"cfg-if",
"cloudabi",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "proc-macro-error"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn-mid",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serene"
version = "0.1.0"
dependencies = [
"clap",
"inkwell",
]
[[package]]
name = "smallvec"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "syn-mid"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
dependencies = [
"linked-hash-map",
]

View File

@ -1,11 +0,0 @@
[package]
name = "serene"
version = "0.1.0"
authors = ["Sameer Rahmani <lxsameer@gnu.org>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.0.0-beta.1", features = ["yaml"] }
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm10-0" }

17
bin/CMakeLists.txt Normal file
View File

@ -0,0 +1,17 @@
add_executable(serene serene.cpp)
target_compile_features(serene PRIVATE cxx_std_20)
target_link_libraries(serene PRIVATE
libserene
${llvm_libs}
#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
)
cotire(serene)

3
bin/serene.cpp Normal file
View File

@ -0,0 +1,3 @@
int main() {
return 0;
}

65
builder.sh Executable file
View File

@ -0,0 +1,65 @@
#! /bin/bash
command=$1
export CCC_CC=clang-10
export CCC_CXX=clang++-10
export CC=clang-10
export CXX=clang++-10
ROOT_DIR=`pwd`
BUILD_DIR=$ROOT_DIR/build
scanbuild=scan-build-10
function build() {
pushd $BUILD_DIR
cmake $ROOT_DIR
make -j 4
popd
}
function clean() {
rm -rf $BUILD_DIR
}
function run() {
pushd $BUILD_DIR
$BUILD_DIR/bin/serene "$@"
popd
}
case "$command" in
"fresh-build")
clean
mkdir -p $BUILD_DIR
build
;;
"build")
build
;;
"run")
run "$@"
;;
"scan-build")
clean
mkdir -p $BUILD_DIR
pushd $BUILD_DIR
exec $scanbuild cmake $ROOT_DIR
exec $scanbuild scan-build make -j 4
popd
;;
"clean")
rm -rf $BUILD_DIR
;;
*)
echo "Commands: "
echo "fresh-build - Build Serene from scratch"
echo "build - reCompiles the project using the already exist cmake configuration"
echo "run - Runs the serene executable"
echo "scan-build - Compiles serene with static analyzer"
echo "clean - :D"
;;
esac

4212
cmake/cotire.cmake Normal file

File diff suppressed because it is too large Load Diff

7
docs/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
doxygen_add_docs(docs
serene/serene.hpp
"${CMAKE_CURRENT_SOURCE_DIR}/index.md"
WORKING_DIRECTORY
"${INCLUDE_DIR}")

View File

@ -0,0 +1,5 @@
#ifndef SERENE_H
#define SERENE_H
#endif

View File

@ -0,0 +1,85 @@
;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
;; Copyright (C) 2010-2020 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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, or (at your option)
;; any later version.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library implements support for looking at Git diffs and
;; commits.
;;; Code:
(eval-when-compile
(require 'ansi-color)
(require 'subr-x))
(require 'git-commit)
(require 'magit-core)
;; For `magit-diff-popup'
(declare-function magit-stash-show "magit-stash" (stash optional args files))
;; For `magit-diff-visit-file'
(declare-function dired-jump "dired-x" (optional other-window file-name))
(declare-function magit-find-file-noselect "magit-files" (rev file))
(declare-function magit-status-setup-buffer "magit-status" (directory))
;; For `magit-diff-while-committing'
(declare-function magit-commit-message-buffer "magit-commit" ())
;; For `magit-insert-revision-gravatar'
(defvar gravatar-size)
;; For `magit-show-commit' and `magit-diff-show-or-scroll'
(declare-function magit-current-blame-chunk "magit-blame" ())
(declare-function magit-blame-mode "magit-blame" (optional arg))
(defvar magit-blame-mode)
;; For `magit-diff-show-or-scroll'
(declare-function git-rebase-current-line "git-rebase" ())
;; For `magit-diff-unmerged'
(declare-function magit-merge-in-progress-p "magit-merge" ())
(declare-function magit--merge-range "magit-merge" (optional head))
;; For `magit-diff--dwim'
(declare-function forge--pullreq-ref "forge-pullreq" (pullreq))
;; For `magit-diff-wash-diff'
(declare-function ansi-color-apply-on-region "ansi-color" (begin end))
(eval-when-compile
(cl-pushnew 'base-ref eieio--known-slot-names)
(cl-pushnew 'orig-rev eieio--known-slot-names)
(cl-pushnew 'action-type eieio--known-slot-names)
(cl-pushnew 'target eieio--known-slot-names))
(require 'diff-mode)
(require 'smerge-mode)
;;; Options
;;;; Diff Mode
(defgroup magit-diff nil
"Inspect and manipulate Git diffs."
link '(info-link "(magit)Diffing")
group 'magit-modes
type 'float)
(asd 234 (asd zxc wqe asd asd rewe asd (asd asd (asd asd asd (123 3213123 'asd 'asd "sadasd" (asd asdsad (zxczxc (asdasd asd asd (asdas asd as 234234 324 (234 234 asd 342 ("asdasd" sadf 234 asd ((((((((((((((((((((((((((((((((asd asd asdasd (((((((((((((asdasdasd (((((((((((((((asdasdasd (asdasdasdasd asdas ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
-234234
ascent
9393

20
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,20 @@
# Note that headers are optional, and do not affect add_library, but they will not
# show up in IDEs unless they are listed in add_library.
# Optionally glob, but only for CMake 3.12 or later:
# file(GLOB HEADER_LIST CONFIGURE_DEPENDS "${ModernCMakeExample_SOURCE_DIR}/include/modern/*.hpp")
set(HEADER_LIST "${INCLUDE_DIR}/serene/serene.hpp")
# Make an automatic library - will be static or dynamic based on user setting
add_library(libserene libserene.cpp ${HEADER_LIST})
# We need this directory, and users of our library will need it too
target_include_directories(libserene PUBLIC "${INCLUDE_DIR}")
target_compile_features(libserene PUBLIC cxx_std_20)
# This depends on (header only) boost
target_link_libraries(libserene ${llvm_libs})
source_group(TREE "${INCLUDE_DIR}" PREFIX "Header Files" FILES ${HEADER_LIST})

View File

@ -1,42 +0,0 @@
use crate::namespace::Namespace;
use crate::types::{ExprResult, Expression, List, Number, Symbol};
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Expr {
Sym(Symbol),
Str(String),
Num(Number),
Comment,
Error(String),
Cons(List<Expr>),
Nil,
NoMatch,
}
impl<'a> Expr {
pub fn make_list(first: Expr, rest: Expr) -> Expr {
Expr::Cons(List::<Expr>::new(Box::new(first), Box::new(rest)))
}
pub fn make_symbol(v: String) -> Expr {
Expr::Sym(Symbol::new(v))
}
pub fn make_string(v: String) -> Expr {
Expr::Str(v)
}
pub fn make_number(n: Number) -> Expr {
Expr::Num(n)
}
}
impl<'a> Expression<'a> for Expr {
fn eval() {}
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
match self {
Expr::Sym(s) => s.code_gen(ns),
_ => Err("NotImplemented".to_string()),
}
}
}

View File

@ -1,17 +0,0 @@
name: myapp
version: "0.1.0"
author: Sameer Rahmani <lxsameer@gnu.org>
about: Serene's compiler
args:
- debug-parser:
long: debug-parser
about: Prints out the AST only.
takes_value: false
- INPUT:
about: Sets the input file to use
required: true
index: 1
- verbose:
short: v
multiple: true
about: Sets the level of verbosity

View File

@ -1,128 +0,0 @@
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::passes::PassManager;
use inkwell::values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, PointerValue};
use crate::namespace::Namespace;
use crate::types::Expression;
use std::collections::HashMap;
// pub fn create_compiler<'ctx>() -> Compiler<'ctx> {
// let default_ns_name = "user";
// // let builder = context.create_builder();
// let context = Context::create();
// //let user_ns = Namespace::new(&context, default_ns_name);
// //namespaces.insert(default_ns_name, &user_ns);
// // let fpm = PassManager::create(&user_ns.module);
// // fpm.add_instruction_combining_pass();
// // fpm.add_reassociate_pass();
// // fpm.add_gvn_pass();
// // fpm.add_cfg_simplification_pass();
// // fpm.add_basic_alias_analysis_pass();
// // fpm.add_promote_memory_to_register_pass();
// // fpm.add_instruction_combining_pass();
// // fpm.add_reassociate_pass();
// // fpm.initialize();
// //, builder, fpm, namespaces, Some(&default_ns_name)
// //Compiler::new(context)
// let builder = context.create_builder();
// Compiler {
// builder: builder,
// context: context,
// namespaces: HashMap::new(),
// }
// }
pub struct Compiler<'ctx> {
pub context: Context,
pub builder: Builder<'ctx>,
// /// This hashmap contains all the namespaces that has to be compiled and
// /// maps two different keys to the same namespace. Since namespace names
// /// can not contain `/` char, the keys of this map are the namespace
// /// name and the path to the file containing the namespace. For example:
// ///
// /// A let's say we have a namespace `abc.xyz`, this namespace will have
// /// two entries in this hashmap. One would be the ns name itself which
// /// is `abc.xyz` in this case and the otherone would be
// /// `/path/to/abc/xyz.srn` file that contains the ns.
pub namespaces: HashMap<&'ctx str, Namespace<'ctx>>,
// pub fpm: &'a PassManager<FunctionValue<'ctx>>,
// current_ns_name: Option<&'a str>,
}
impl<'ctx> Compiler<'ctx> {
pub fn new() -> Compiler<'ctx> {
let default_ns_name = "user";
// let builder = context.create_builder();
let context = Context::create();
//let user_ns = Namespace::new(&context, default_ns_name);
//namespaces.insert(default_ns_name, &user_ns);
// let fpm = PassManager::create(&user_ns.module);
// fpm.add_instruction_combining_pass();
// fpm.add_reassociate_pass();
// fpm.add_gvn_pass();
// fpm.add_cfg_simplification_pass();
// fpm.add_basic_alias_analysis_pass();
// fpm.add_promote_memory_to_register_pass();
// fpm.add_instruction_combining_pass();
// fpm.add_reassociate_pass();
// fpm.initialize();
//, builder, fpm, namespaces, Some(&default_ns_name)
//Compiler::new(context)
let builder = context.create_builder();
Compiler {
builder: builder,
context: context,
namespaces: HashMap::new(),
}
}
// #[inline]
// pub fn current_ns(&self) -> Option<&'a Namespace<'a, 'ctx>> {
// let ns = self.current_ns_name?;
// self.namespaces.get(ns).map(|x| *x)
// }
// /// Returns the `FunctionValue` representing the function being compiled.
// #[inline]
// pub fn current_fn(&self) -> FunctionValue<'ctx> {
// self.current_ns().unwrap().current_fn()
// }
// /// Creates a new stack allocation instruction in the entry block of the function.
// // fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> {
// // let builder = self.context.create_builder();
// // let entry = self.current_fn().get_first_basic_block().unwrap();
// // match entry.get_first_instruction() {
// // Some(first_instr) => builder.position_before(&first_instr),
// // None => builder.position_at_end(entry),
// // }
// // builder.build_alloca(self.context.f64_type(), name)
// // }
// pub fn compile(
// &self,
// exprs: Vec<&impl Expression<'ctx>>,
// ) -> Vec<Result<PointerValue<'ctx>, String>> {
// let current_ns = match self.current_ns() {
// Some(ns) => ns,
// None => panic!("Current namespace is not set."),
// };
// let mut generated_code = vec![];
// for expr in &exprs {
// let code = expr.code_gen(current_ns);
// generated_code.push(code);
// }
// generated_code
// }
}

3
src/libserene.cpp Normal file
View File

@ -0,0 +1,3 @@
int read() {
return 0;
}

View File

@ -1,34 +0,0 @@
extern crate inkwell;
use clap::{load_yaml, App};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::string::String;
pub mod ast;
pub mod compiler;
pub mod namespace;
pub mod reader;
pub mod scope;
pub mod types;
fn main() -> io::Result<()> {
let yaml = load_yaml!("cli.yml");
let args = App::from(yaml).get_matches();
//let compiler = create_compiler();
if let Some(input) = args.value_of("INPUT") {
let mut f = File::open(input)?;
let mut buf = String::new();
f.read_to_string(&mut buf)?;
match reader::read_string(&buf) {
Ok(v) => println!("{:?}", v),
Err(e) => println!(">> error {:?}", e),
}
} else {
println!("Input file is missing.")
}
Ok(())
}

View File

@ -1,35 +0,0 @@
use crate::scope::Scope;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::values::FunctionValue;
pub struct Namespace<'ctx> {
/// Each namespace in serene contains it's own LLVM module. You can
/// think of modules as compilation units. Object files if you prefer.
/// This way we should be able to hot swap the namespaces.
pub module: Module<'ctx>,
scope: Scope<'ctx>,
// // The option of the current function being compiled
// current_fn_opt: Option<FunctionValue<'ctx>>,
}
impl<'ctx> Namespace<'ctx> {
pub fn new(context: &'ctx Context, name: &str) -> Namespace<'ctx> {
Namespace {
module: context.create_module(&name),
scope: Scope::new(None),
// current_fn_opt: None,
}
}
// /// Gets a defined function given its name.
// #[inline]
// pub fn get_function(&self, name: &str) -> Option<FunctionValue<'ctx>> {
// self.module.get_function(name)
// }
// /// Returns the `FunctionValue` representing the function being compiled.
// #[inline]
// pub fn current_fn(&self) -> FunctionValue<'ctx> {
// self.current_fn_opt.unwrap()
// }
}

View File

@ -1,355 +0,0 @@
use crate::ast::Expr;
use crate::types::Number;
use std::io::{BufReader, Read};
pub type ReadResult<'a> = Result<Expr, String>;
pub struct ExprReader {
location: i32,
read_stack: Vec<char>,
}
impl ExprReader {
fn new() -> ExprReader {
ExprReader {
location: 0,
read_stack: vec![],
}
}
/// Retun a single character by reading from the `reader`. ,
///
/// # Arguments:
///
/// * `reader`: The buffer to read from.
/// * `skip_whitespace`: Whether or not to skip whitespace chars. *Bear in mind that
/// if you care about the newline char you should not skip the whitespaces*.
fn get_char<T: Read>(
&mut self,
reader: &mut BufReader<T>,
skip_whitespace: bool,
) -> Option<char> {
loop {
match self.read_stack.pop() {
Some(c) if !c.is_whitespace() || !skip_whitespace => return Some(c),
Some(_) => continue,
None => (),
};
// Rust is weird, it doesn't provide a way to read from a buffer char by char.
let mut single_char_buff = [0];
let bytes_read = reader.read(&mut single_char_buff);
match bytes_read {
Ok(n) if n > 0 => self.location = self.location + 1,
Ok(_) => return None,
Err(_) => return None,
};
let ch = single_char_buff[0] as char;
match ch {
c if !c.is_whitespace() || !skip_whitespace => return Some(c),
_ => (),
};
}
}
fn unget_char(&mut self, c: char) {
self.read_stack.push(c);
}
// Look ahead. AFAIK Rust doesn't provide any unread functoinality like Java input streams which
// sucks.
fn peek_char<T: Read>(
&mut self,
reader: &mut BufReader<T>,
skip_whitespace: bool,
) -> Option<char> {
match self.get_char(reader, skip_whitespace) {
Some(c) => {
self.unget_char(c);
Some(c)
}
None => None,
}
}
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
let rest = self.read_expr(reader)?;
Ok(Expr::make_list(
Expr::make_symbol("quote".to_string()),
rest,
))
}
fn read_unquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
match self.peek_char(reader, true) {
Some('@') => {
// Move forward in the buffer since we peeked it
let _ = self.get_char(reader, true);
let rest = self.read_expr(reader)?;
Ok(Expr::make_list(
Expr::make_symbol("unquote-splicing".to_string()),
rest,
))
}
_ => {
let rest = self.read_expr(reader)?;
Ok(Expr::make_list(
Expr::make_symbol("unquote".to_string()),
rest,
))
}
}
}
fn read_quasiquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
let rest = self.read_expr(reader)?;
Ok(Expr::make_list(
Expr::make_symbol("quasiquote".to_string()),
rest,
))
}
// TODO: We might want to replace Cons with an actual List struct
fn read_list<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
let first = match self.read_expr(reader) {
Ok(value) => value,
Err(e) => match self.get_char(reader, true) {
// is it an empty list ?
// TODO: we might want to return an actual empty list here
Some(')') => return Ok(Expr::Nil),
_ => return Err(e),
},
};
let rest = match self.get_char(reader, true) {
Some(e) => {
self.unget_char(e);
self.read_list(reader)?
}
None => return Err("Unexpected EOF while parsing a list.".to_string()),
};
Ok(Expr::make_list(first, rest))
}
fn is_valid_for_identifier(&self, c: char) -> bool {
match c {
'!'
| '$'
| '%'
| '&'
| '*'
| '+'
| '-'
| '.'
| '~'
| '/'
| ':'
| '<'
| '='
| '>'
| '?'
| '@'
| '^'
| '_'
| 'a'..='z'
| 'A'..='Z'
| '0'..='9' => true,
_ => false,
}
}
fn _read_symbol<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
let mut symbol = match self.peek_char(reader, false) {
Some(e) if self.is_valid_for_identifier(e) => {
// Read into string
let ch = self.get_char(reader, false).unwrap();
let mut s = String::new();
s.push(ch);
s
}
Some(e) => {
return Err(format!(
"Unexpected character: got '{}', expected a symbol at {}",
e, self.location
))
}
None => return Err("Unexpected EOF".to_string()),
};
loop {
match self.get_char(reader, false) {
Some(v) if self.is_valid_for_identifier(v) => symbol.push(v),
Some(v) => {
self.unget_char(v);
break;
}
None => break,
}
}
Ok(Expr::make_symbol(symbol))
}
fn read_escape_char<T: Read>(&mut self, reader: &mut BufReader<T>) -> Option<char> {
match self.get_char(reader, false) {
Some(e) => match e {
'\"' => Some('\"'),
'\'' => Some('\''),
'\\' => Some('\\'),
'n' => Some('\n'),
'r' => Some('\r'),
't' => Some('\t'),
_ => None,
},
None => None,
}
}
fn read_string<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
// Skip the " char
let _ = self.get_char(reader, false);
let mut string = "".to_string();
loop {
match self.get_char(reader, false) {
Some(e) => match e {
'\"' => break,
'\\' => match self.read_escape_char(reader) {
Some(v) => string.push(v),
None => return Err(format!("Unexpected char to escape, got {}", e)),
},
//'\n' => return Err("Unescaped newlines are not allowed in string literals".to_string()),
_ => string.push(e),
},
None => return Err("Unexpected EOF while scanning a string".to_string()),
}
}
Ok(Expr::make_string(string))
}
fn read_number<T: Read>(&mut self, reader: &mut BufReader<T>, neg: bool) -> ReadResult {
let mut is_double = false;
let mut string = (if neg { "-" } else { "" }).to_string();
loop {
match self.get_char(reader, false) {
Some(e) if e == '.' && is_double => {
return Err("A double with more that one '.' ???".to_string())
}
Some(e) if e == '.' => {
is_double = true;
string.push(e);
}
Some(e) if e.is_digit(10) => string.push(e),
Some(e) => {
self.unget_char(e);
break;
}
None => break,
}
}
// TODO: Move this to ast module and use the `new` function on
// Number struct
if is_double {
Ok(Expr::make_number(Number::Float(
string.parse::<f64>().unwrap(),
)))
} else {
Ok(Expr::make_number(Number::Integer(
string.parse::<i64>().unwrap(),
)))
}
}
fn read_symbol<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
match self.peek_char(reader, true) {
Some(c) => match c {
'\"' => self.read_string(reader),
c if c.is_digit(10) => self.read_number(reader, false),
// ':' => self.read_keyword(reader),
'-' => {
// Read the '-' char
let _ = self.get_char(reader, true);
match self.peek_char(reader, true) {
Some(ch) => match ch {
ch if ch.is_digit(10) => self.read_number(reader, true),
_ => {
self.unget_char(c);
self._read_symbol(reader)
}
},
None => {
self.unget_char(c);
self._read_symbol(reader)
}
}
}
_ => self._read_symbol(reader),
},
None => Err("Unexpected EOF while scanning atom".to_string()),
}
}
pub fn ignore_comments<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
match self.get_char(reader, false) {
Some(c) => match c {
'\n' => Ok(Expr::Comment),
_ => self.ignore_comments(reader),
},
None => Ok(Expr::Comment),
}
}
pub fn read_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
match self.get_char(reader, true) {
Some(c) => {
match c {
'\'' => self.read_quoted_expr(reader),
'~' => self.read_unquoted_expr(reader),
'`' => self.read_quasiquoted_expr(reader),
'(' => self.read_list(reader),
';' => self.ignore_comments(reader),
//'[' => self.read_vector(reader),
//'{' => self.read_map(reader),
_ => {
self.unget_char(c);
self.read_symbol(reader)
}
}
}
None => Ok(Expr::NoMatch),
}
}
pub fn read_from_buffer<T: Read>(
&mut self,
reader: &mut BufReader<T>,
) -> Result<Vec<Expr>, String> {
let mut ast = vec![];
loop {
match self.read_expr(reader) {
Ok(Expr::NoMatch) => break,
Err(v) => return Err(v),
Ok(Expr::Comment) => continue,
Ok(v) => ast.push(v),
}
}
Ok(ast)
}
pub fn read(&mut self, string: &str) -> Result<Vec<Expr>, String> {
let reader = BufReader::new(string.as_bytes());
let mut buf_reader = BufReader::new(reader);
self.read_from_buffer(&mut buf_reader)
}
}
pub fn read_string(input: &str) -> Result<Vec<Expr>, String> {
let mut reader = ExprReader::new();
reader.read(input)
}

View File

@ -1,29 +0,0 @@
use inkwell::values::PointerValue;
use std::collections::HashMap;
pub struct Scope<'a> {
parent: Option<Box<Scope<'a>>>,
symbol_table: HashMap<String, PointerValue<'a>>,
}
impl<'a> Scope<'a> {
pub fn new(_parent: Option<Scope>) -> Scope {
let p = match _parent {
Some(x) => Some(Box::new(x)),
None => None,
};
Scope {
parent: p,
symbol_table: HashMap::new(),
}
}
pub fn lookup(&self, key: &str) -> Option<PointerValue> {
self.symbol_table.get(key).map(|x| *x)
}
pub fn insert(&mut self, key: &str, val: PointerValue<'a>) {
self.symbol_table.insert(key.to_string(), val);
}
}

View File

@ -1,9 +0,0 @@
pub mod core;
pub mod list;
pub mod number;
pub mod symbol;
pub use self::core::{ExprResult, Expression};
pub use self::list::List;
pub use self::number::Number;
pub use self::symbol::Symbol;

View File

@ -1,9 +0,0 @@
use crate::namespace::Namespace;
use inkwell::values::PointerValue;
pub type ExprResult<'a> = Result<PointerValue<'a>, String>;
pub trait Expression<'a> {
fn eval();
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a>;
}

View File

@ -1,33 +0,0 @@
use crate::namespace::Namespace;
use crate::types::core::{ExprResult, Expression};
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct List<T>
where
for<'a> T: Expression<'a>,
{
first: Box<T>,
rest: Box<T>,
}
impl<T> List<T>
where
for<'a> T: Expression<'a>,
{
pub fn new<S>(first: Box<S>, rest: Box<S>) -> List<S>
where
for<'a> S: Expression<'a>,
{
List { first, rest }
}
}
impl<'a, T> Expression<'a> for List<T>
where
for<'b> T: Expression<'b>,
{
fn eval() {}
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
Err("Not implemented on list".to_string())
}
}

View File

@ -1,36 +0,0 @@
use crate::namespace::Namespace;
use crate::types::core::{ExprResult, Expression};
// Note: I kept the number implementation simple for now
// but we need to decide on our approach to numbers, are
// we going to only support the 64bit variants? or should
// try to be smart and support 32 and 64 and switch between
// them ?
// What about usize and isize ?
#[derive(Debug, Clone)]
pub enum Number {
Integer(i64),
Float(f64),
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
// TODO: Eval other
let comb = (&self, &other);
match comb {
(Number::Integer(x), Number::Integer(y)) => *x == *y,
(Number::Float(x), Number::Float(y)) => *x == *y,
(Number::Integer(x), Number::Float(y)) => *x as f64 == *y,
(Number::Float(x), Number::Integer(y)) => *x == *y as f64,
}
}
}
impl Eq for Number {}
impl<'a> Expression<'a> for Number {
fn eval() {}
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
Err("Not implemented on numbers".to_string())
}
}

View File

@ -1,29 +0,0 @@
use crate::namespace::Namespace;
use crate::types::core::{ExprResult, Expression};
use inkwell::values::PointerValue;
#[derive(Debug, Clone)]
pub struct Symbol {
name: String,
}
impl PartialEq for Symbol {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for Symbol {}
impl<'a> Expression<'a> for Symbol {
fn eval() {}
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
Err("Not implemented on symbol".to_string())
}
}
impl Symbol {
pub fn new(name: String) -> Self {
Symbol { name }
}
}

20
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,20 @@
# Testing library
FetchContent_Declare(
catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.9.1
)
FetchContent_MakeAvailable(catch2)
# Tests need to be added as executables first
add_executable(tests serenetests.cpp)
target_compile_features(tests PRIVATE cxx_std_20)
# Should be linked to the main library, as well as the Catch2 testing library
target_link_libraries(tests PRIVATE libserene Catch2::Catch2)
# If you register a test, then ctest and make test will run it.
# You can also run examples and check the output, as well.
# add_test(NAME testlibtest serene testlib) # Command can be a target

3
tests/serenetests.cpp Normal file
View File

@ -0,0 +1,3 @@
int main() {
return 0;
}