├── .clang-format
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── Readme.md
├── cmake
├── CMakeLists.txt
├── compiler
│ ├── clang.cmake
│ ├── gcc.cmake
│ └── msvc.cmake
├── configure_compiler.cmake
├── configure_macros.cmake
├── configure_platform.cmake
├── macros
│ ├── auto_collect.cmake
│ ├── compile_features.cmake
│ ├── configure_llvm.cmake
│ └── group_sources.cmake
└── platform
│ ├── unix.cmake
│ └── windows.cmake
├── dep
├── CMakeLists.txt
├── antlr4
│ └── CMakeLists.txt
├── cotire
│ └── CMakeLists.txt
├── fmt
│ └── CMakeLists.txt
└── function2
│ └── CMakeLists.txt
├── doc
├── .gitignore
└── Doxyfile
├── lang
└── main.swy
└── src
├── AST
├── AST.cpp
├── AST.hpp
├── AST.inl
├── ASTCloner.cpp
├── ASTCloner.hpp
├── ASTContext.cpp
├── ASTContext.hpp
├── ASTCursor.cpp
├── ASTCursor.hpp
├── ASTFragment.hpp
├── ASTPredicate.hpp
├── ASTScope.cpp
├── ASTScope.hpp
├── ASTStringer.cpp
├── ASTStringer.hpp
├── ASTTraversal.hpp
└── ASTVisitor.hpp
├── CMakeLists.txt
├── Codegen
├── CodeExecutor.cpp
├── CodeExecutor.hpp
├── CodegenBase.cpp
├── CodegenBase.hpp
├── CodegenInstance.cpp
├── CodegenInstance.hpp
├── FunctionCodegen.cpp
├── FunctionCodegen.hpp
├── IRContext.cpp
├── IRContext.hpp
├── MetaCodegen.cpp
├── MetaCodegen.hpp
├── NameMangeling.cpp
└── NameMangeling.hpp
├── Diag
├── Diagnostic.cpp
├── Diagnostic.hpp
├── Diagnostic.inl
├── DiagnosticBuilder.cpp
├── DiagnosticBuilder.hpp
├── DiagnosticEngine.cpp
├── DiagnosticEngine.hpp
├── DiagnosticListener.cpp
├── DiagnosticListener.hpp
├── SourceAnnotated.hpp
├── SourceLocation.cpp
├── SourceLocation.hpp
└── SourceLocationResolver.hpp
├── Frontend
├── CompilationUnit.cpp
├── CompilationUnit.hpp
├── CompilerInstance.cpp
├── CompilerInstance.hpp
├── CompilerInvocation.cpp
└── CompilerInvocation.hpp
├── Main.cpp
├── PCH
└── PCH.hpp
├── Parse
├── ASTLayout.cpp
├── ASTLayout.hpp
├── ASTParser.cpp
├── ASTParser.hpp
├── BasicASTBuilder.cpp
├── BasicASTBuilder.hpp
├── BasicParser.cpp
├── BasicParser.hpp
├── BasicTreeSupport.cpp
├── BasicTreeSupport.hpp
├── BasicTreeVisitor.cpp
├── BasicTreeVisitor.hpp
├── GeneratedLexer.g4
├── GeneratedParser.g4
├── LocalScopeVisitor.cpp
└── LocalScopeVisitor.hpp
├── Sema
├── DependencyAnalysis.cpp
├── DependencyAnalysis.hpp
├── SemaAnalysis.cpp
└── SemaAnalysis.hpp
├── Support
├── Formatting.hpp
├── Hash.hpp
├── NonCopyable.hpp
├── Nullable.hpp
├── Ownership.hpp
├── ScopeLeaveAction.hpp
└── Traits.hpp
└── Tooling
├── ASTDumper.cpp
├── ASTDumper.hpp
├── TokenDumper.cpp
└── TokenDumper.hpp
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: LLVM
2 |
3 | PointerAlignment: Left
4 | IndentCaseLabels: true
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Compiled Dynamic libraries
12 | *.so
13 | *.dylib
14 | *.dll
15 |
16 | # Fortran module files
17 | *.mod
18 |
19 | # Compiled Static libraries
20 | *.lai
21 | *.la
22 | *.a
23 | *.lib
24 |
25 | # Executables
26 | *.exe
27 | *.out
28 | *.app
29 |
30 | # User-specific files
31 | *.suo
32 | *.user
33 | *.userosscache
34 | *.sln.docstates
35 |
36 | # Build results
37 | [Dd]ebug/
38 | [Dd]ebugPublic/
39 | [Rr]elease/
40 | [Rr]eleases/
41 | x64/
42 | x86/
43 | build/
44 | bld/
45 | [Bb]in/
46 | [Oo]bj/
47 |
48 | # Visual Studo 2015 cache/options directory
49 | .vs/
50 |
51 | # Temporary files
52 | *.TMP
53 |
54 | cloc.sh
55 | cloc_lang_def.txt
56 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "dep/fmt/fmt"]
2 | path = dep/fmt/fmt
3 | url = https://github.com/fmtlib/fmt.git
4 | [submodule "dep/antlr4/antlr4"]
5 | path = dep/antlr4/antlr4
6 | url = https://github.com/antlr/antlr4.git
7 | [submodule "dep/function2/function2"]
8 | path = dep/function2/function2
9 | url = https://github.com/Naios/function2.git
10 | [submodule "dep/cotire/cotire"]
11 | path = dep/cotire/cotire
12 | url = https://github.com/sakra/cotire.git
13 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
2 | project(compiler LANGUAGES C CXX)
3 |
4 | enable_testing()
5 | set_property(GLOBAL PROPERTY USE_FOLDERS ON)
6 |
7 | option(USE_PCH "Use precompiled headers" ON)
8 |
9 | include(cmake/CMakeLists.txt)
10 | if (USE_PCH)
11 | include(dep/cotire/CMakeLists.txt)
12 | endif()
13 |
14 | add_subdirectory(dep)
15 |
16 | add_subdirectory(src)
17 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | swy
9 |
A static language for homogeneous meta-programming
10 |
11 |
12 | ---
13 |
14 | ## Introduction
15 |
16 | This is my personal experimental educational research compiler which originally powered my bachelor's thesis: *"An Imperative Programming Language with Compile-time Homogeneous Meta-Programming"*. It's built on *LLVM* and *ANTLR* and features my own language for homogeneous meta-programming where we can do compile-time evaluations with the same language we use for run-time programming. Internally the compiler uses an LLVM ORC-JIT for evaluating expressions at compile-time as well as generating new code based upon those evaluations.
17 |
18 | To be honest, I always wanted to invent my own programming language (like most enthusiastic developers), so I took the chance when I thought about a possible topic for a bachelor's thesis while keeping a special research in mind.
19 |
20 | The overall project was developed in ~40 days, currently it's far away from being perfect, however I tried to keep the standards in software design high.
21 |
22 | ## Software Architecture
23 |
24 | The compilation pipeline slightly differs from existing languages for allowing homogeneous meta-programming, the compiler uses a flat unstructured representation of AST nodes which makes deep cloning easy:
25 |
26 |
27 |
28 |
29 |
30 | ## Design patterns
31 |
32 | The compiler itself uses a lot of C++ meta programming, for instance there are traversel functions which can up-cast AST nodes to their real type (this is a modern visitor replacement):
33 |
34 | ```c++
35 | ASTNode* node = ...;
36 |
37 | traverseNodeExpecting(node, pred::hasChildren(), [&](auto promoted) {
38 | // Static AST predicates: ^^^^^^^^^^^^^^^^^^^ we expect a node with children
39 |
40 | // `promoted` has the type of the node, the lambda is instantiated multiple times
41 | return std::count(promoted->children.begin(), promoted->children.end());
42 | });
43 | ```
44 |
45 |
46 | ## Requirements
47 |
48 | ### Installation Instructions
49 |
50 | #### Windows
51 |
52 | Requirements:
53 |
54 | - CMake
55 | - Java 8
56 |
57 | Build LLVM and run the CMake GUI on the compiler source
58 |
59 | Select the LLVM cmake config
60 |
61 | #### Linux
62 |
63 | Requirements:
64 |
65 | - CMake
66 | - Java 8
67 |
68 |
69 | Due to the usage of the ANTLR framework we have to build LLVM with RTTI support enabled:
70 |
71 | ```sh
72 | git clone http://llvm.org/git/llvm.git
73 | cd llvm
74 | git checkout release_39
75 |
76 | mkdir build
77 | cd build
78 | cmake .. -DCMAKE_INSTALL_PREFIX=~/llvm-rtti \
79 | -DCMAKE_BUILD_TYPE=Release \
80 | -DLLVM_ENABLE_ASSERTIONS=OFF \
81 | -DLLVM_TARGETS_TO_BUILD="X86" \
82 | -DLLVM_ENABLE_RTTI=ON
83 |
84 | make -j8
85 | make install
86 | ```
87 |
88 | Build the compiler:
89 |
90 | ```sh
91 | mkdir build
92 | cd build
93 |
94 | cmake -DLLVM_DIR=~/llvm-rtti/lib/cmake/llvm \
95 | -DANTLR_USE_PATH_JAVA=ON -DUSE_PCH=OFF ..
96 |
97 | make -j8
98 | ```
99 |
100 |
101 |
--------------------------------------------------------------------------------
/cmake/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include("${CMAKE_CURRENT_LIST_DIR}/configure_macros.cmake")
2 | include("${CMAKE_CURRENT_LIST_DIR}/configure_platform.cmake")
3 | include("${CMAKE_CURRENT_LIST_DIR}/configure_compiler.cmake")
4 |
5 | include(InstallRequiredSystemLibraries)
6 | include(CPack)
7 |
--------------------------------------------------------------------------------
/cmake/compiler/clang.cmake:
--------------------------------------------------------------------------------
1 | # Enable full warnings
2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra")
3 |
4 | # Disabled Exceptions
5 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
6 |
--------------------------------------------------------------------------------
/cmake/compiler/gcc.cmake:
--------------------------------------------------------------------------------
1 | # Enable full warnings
2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra")
3 |
4 | # Disabled Exceptions
5 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
6 |
--------------------------------------------------------------------------------
/cmake/compiler/msvc.cmake:
--------------------------------------------------------------------------------
1 | if (${MSVC_VERSION} LESS 1900)
2 | message(FATAL_ERROR "You are using an unsupported version of Visual Studio "
3 | "which doesn't support all required C++14 features. "
4 | "(Visual Studio 2015 (version >= 1900) is required!)")
5 | endif()
6 |
7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
8 |
9 | if(CMAKE_SIZEOF_VOID_P MATCHES 8)
10 | set(PLATFORM 64)
11 | else()
12 | set(PLATFORM 32)
13 | endif()
14 |
15 | if (PLATFORM EQUAL 64)
16 | add_definitions("-D_WIN64")
17 | endif()
18 |
19 | # Enable full warnings
20 | string(REGEX REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
22 |
23 | # Enable multithreaded compilation
24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
25 |
26 | # Disable exceptions
27 | # add_definitions(-D_HAS_EXCEPTIONS=0)
28 | # string(REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
29 |
--------------------------------------------------------------------------------
/cmake/configure_compiler.cmake:
--------------------------------------------------------------------------------
1 | # Select the compiler specific cmake file
2 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
3 | include("${CMAKE_CURRENT_LIST_DIR}/compiler/clang.cmake")
4 | elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
5 | include("${CMAKE_CURRENT_LIST_DIR}/compiler/gcc.cmake")
6 | elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
7 | include("${CMAKE_CURRENT_LIST_DIR}/compiler/msvc.cmake")
8 | else()
9 | message(FATAL_ERROR "Unknown compiler!")
10 | endif()
11 |
--------------------------------------------------------------------------------
/cmake/configure_macros.cmake:
--------------------------------------------------------------------------------
1 | # Register all macros
2 | file(GLOB LOCALE_MACRO_FILES
3 | "${CMAKE_CURRENT_LIST_DIR}/macros/*.cmake"
4 | )
5 | foreach (LOCALE_MACRO_FILE ${LOCALE_MACRO_FILES})
6 | include("${LOCALE_MACRO_FILE}")
7 | endforeach()
8 |
--------------------------------------------------------------------------------
/cmake/configure_platform.cmake:
--------------------------------------------------------------------------------
1 | # Select the platform specific cmake file
2 | if (WIN32)
3 | include("${CMAKE_CURRENT_LIST_DIR}/platform/windows.cmake")
4 | elseif (UNIX)
5 | include("${CMAKE_CURRENT_LIST_DIR}/platform/unix.cmake")
6 | else()
7 | message(FATAL_ERROR "Unknown platform!")
8 | endif()
9 |
--------------------------------------------------------------------------------
/cmake/macros/auto_collect.cmake:
--------------------------------------------------------------------------------
1 | # Collects all source files into the given variable,
2 | # which is useful to include all sources in subdirectories.
3 | # Ignores full qualified directories listed in the variadic arguments.
4 | #
5 | # Use it like:
6 | # CollectSourceFiles(
7 | # ${CMAKE_CURRENT_SOURCE_DIR}
8 | # COMMON_PRIVATE_SOURCES
9 | # # Exclude
10 | # ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders
11 | # ${CMAKE_CURRENT_SOURCE_DIR}/Platform)
12 | #
13 | function(CollectSourceFiles current_dir variable)
14 | list(FIND ARGN "${current_dir}" IS_EXCLUDED)
15 | if(IS_EXCLUDED EQUAL -1)
16 | file(GLOB COLLECTED_SOURCES
17 | ${current_dir}/*.c
18 | ${current_dir}/*.cc
19 | ${current_dir}/*.cpp
20 | ${current_dir}/*.inl
21 | ${current_dir}/*.def
22 | ${current_dir}/*.h
23 | ${current_dir}/*.hh
24 | ${current_dir}/*.hpp)
25 | list(APPEND ${variable} ${COLLECTED_SOURCES})
26 |
27 | file(GLOB SUB_DIRECTORIES ${current_dir}/*)
28 | foreach(SUB_DIRECTORY ${SUB_DIRECTORIES})
29 | if (IS_DIRECTORY ${SUB_DIRECTORY})
30 | CollectSourceFiles("${SUB_DIRECTORY}" "${variable}" "${ARGN}")
31 | endif()
32 | endforeach()
33 | set(${variable} ${${variable}} PARENT_SCOPE)
34 | endif()
35 | endfunction()
36 |
37 | # Collects all subdirectoroies into the given variable,
38 | # which is useful to include all subdirectories.
39 | # Ignores full qualified directories listed in the variadic arguments.
40 | #
41 | # Use it like:
42 | # CollectIncludeDirectories(
43 | # ${CMAKE_CURRENT_SOURCE_DIR}
44 | # COMMON_PUBLIC_INCLUDES
45 | # # Exclude
46 | # ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders
47 | # ${CMAKE_CURRENT_SOURCE_DIR}/Platform)
48 | #
49 | function(CollectIncludeDirectories current_dir variable)
50 | list(FIND ARGN "${current_dir}" IS_EXCLUDED)
51 | if(IS_EXCLUDED EQUAL -1)
52 | list(APPEND ${variable} ${current_dir})
53 | file(GLOB SUB_DIRECTORIES ${current_dir}/*)
54 | foreach(SUB_DIRECTORY ${SUB_DIRECTORIES})
55 | if (IS_DIRECTORY ${SUB_DIRECTORY})
56 | CollectIncludeDirectories("${SUB_DIRECTORY}" "${variable}" "${ARGN}")
57 | endif()
58 | endforeach()
59 | set(${variable} ${${variable}} PARENT_SCOPE)
60 | endif()
61 | endfunction()
62 |
--------------------------------------------------------------------------------
/cmake/macros/compile_features.cmake:
--------------------------------------------------------------------------------
1 | set(CXX11_FEATURES
2 | cxx_alias_templates
3 | cxx_auto_type
4 | cxx_constexpr
5 | cxx_decltype
6 | cxx_decltype_auto
7 | cxx_final
8 | cxx_lambdas
9 | cxx_nullptr
10 | cxx_override)
11 |
12 | set(CXX14_FEATURES
13 | ${CXX11_FEATURES}
14 | # cxx_aggregate_default_initializers
15 | cxx_alignas
16 | cxx_alignof
17 | cxx_attributes
18 | cxx_attribute_deprecated
19 | cxx_binary_literals
20 | cxx_contextual_conversions
21 | # cxx_decltype_incomplete_return_types
22 | cxx_default_function_template_args
23 | cxx_defaulted_functions
24 | cxx_defaulted_move_initializers
25 | cxx_delegating_constructors
26 | cxx_deleted_functions
27 | cxx_digit_separators
28 | cxx_enum_forward_declarations
29 | cxx_explicit_conversions
30 | cxx_extended_friend_declarations
31 | cxx_extern_templates
32 | cxx_func_identifier
33 | cxx_generalized_initializers
34 | cxx_generic_lambdas
35 | cxx_inheriting_constructors
36 | cxx_inline_namespaces
37 | cxx_lambda_init_captures
38 | cxx_local_type_template_args
39 | cxx_long_long_type
40 | cxx_noexcept
41 | cxx_nonstatic_member_init
42 | cxx_range_for
43 | cxx_raw_string_literals
44 | cxx_reference_qualified_functions
45 | # cxx_relaxed_constexpr
46 | cxx_return_type_deduction
47 | cxx_right_angle_brackets
48 | cxx_rvalue_references
49 | cxx_sizeof_member
50 | cxx_static_assert
51 | cxx_strong_enums
52 | cxx_thread_local
53 | cxx_trailing_return_types
54 | cxx_unicode_literals
55 | cxx_uniform_initialization
56 | cxx_unrestricted_unions
57 | cxx_user_literals
58 | # cxx_variable_templates
59 | cxx_variadic_macros
60 | cxx_variadic_templates
61 | cxx_template_template_parameters)
62 |
--------------------------------------------------------------------------------
/cmake/macros/configure_llvm.cmake:
--------------------------------------------------------------------------------
1 | find_package(LLVM 3.9.1 EXACT REQUIRED CONFIG)
2 |
3 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
4 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
5 |
6 | llvm_map_components_to_libnames(llvm_libs
7 | native
8 | target
9 | support
10 | core
11 | option
12 | irreader
13 | passes
14 | orcjit
15 | interpreter
16 | mc
17 | mcdisassembler
18 | mcjit
19 | mcparser
20 | objcarcopts
21 | )
22 |
23 | add_library(llvm INTERFACE IMPORTED GLOBAL)
24 |
25 | set_property(TARGET llvm PROPERTY
26 | INTERFACE_INCLUDE_DIRECTORIES
27 | "${LLVM_INCLUDE_DIRS}")
28 |
29 | set_property(TARGET llvm PROPERTY
30 | INTERFACE_LINK_LIBRARIES
31 | "${llvm_libs}")
32 |
33 | add_definitions(${LLVM_DEFINITIONS})
34 |
35 | # TODO
36 | #set_property(TARGET llvm PROPERTY
37 | # INTERFACE_COMPILE_DEFINITIONS
38 | # "${LLVM_DEFINITIONS}")
39 |
40 | set_property(TARGET llvm PROPERTY
41 | INTERFACE_COMPILE_FEATURES
42 | cxx_defaulted_functions
43 | cxx_defaulted_move_initializers
44 | cxx_decltype_auto
45 | cxx_decltype
46 | cxx_constexpr
47 | cxx_auto_type)
48 |
--------------------------------------------------------------------------------
/cmake/macros/group_sources.cmake:
--------------------------------------------------------------------------------
1 | set(WITH_SOURCE_TREE "hierarchical")
2 | macro(group_sources dir)
3 | # Skip this if WITH_SOURCE_TREE is not set (empty string).
4 | if (NOT ${WITH_SOURCE_TREE} STREQUAL "")
5 | # Include all header and c files
6 | file(GLOB_RECURSE elements RELATIVE ${dir} *.h *.hpp *.inl *.inc *.c *.cpp *.cc)
7 |
8 | foreach(element ${elements})
9 | # Extract filename and directory
10 | get_filename_component(element_name ${element} NAME)
11 | get_filename_component(element_dir ${element} DIRECTORY)
12 |
13 | if (NOT ${element_dir} STREQUAL "")
14 | # If the file is in a subdirectory use it as source group.
15 | if (${WITH_SOURCE_TREE} STREQUAL "flat")
16 | # Build flat structure by using only the first subdirectory.
17 | string(FIND ${element_dir} "/" delemiter_pos)
18 | if (NOT ${delemiter_pos} EQUAL -1)
19 | string(SUBSTRING ${element_dir} 0 ${delemiter_pos} group_name)
20 | source_group("${group_name}" FILES ${dir}/${element})
21 | else()
22 | # Build hierarchical structure.
23 | # File is in root directory.
24 | source_group("${element_dir}" FILES ${dir}/${element})
25 | endif()
26 | else()
27 | # Use the full hierarchical structure to build source_groups.
28 | string(REPLACE "/" "\\" group_name ${element_dir})
29 | source_group("${group_name}" FILES ${dir}/${element})
30 | endif()
31 | else()
32 | # If the file is in the root directory, place it in the root source_group.
33 | source_group("\\" FILES ${dir}/${element})
34 | endif()
35 | endforeach()
36 | endif()
37 | endmacro()
38 |
--------------------------------------------------------------------------------
/cmake/platform/unix.cmake:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Naios/swy/c48f7eb4322aa7fd44a3bb82259787b89292733b/cmake/platform/unix.cmake
--------------------------------------------------------------------------------
/cmake/platform/windows.cmake:
--------------------------------------------------------------------------------
1 | # Windows 7
2 | add_definitions(-D_WIN32_WINNT=0x06010000)
3 |
--------------------------------------------------------------------------------
/dep/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(antlr4)
2 | add_subdirectory(fmt)
3 | add_subdirectory(function2)
4 |
--------------------------------------------------------------------------------
/dep/antlr4/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(CPP_RUNTIME_PATH "${CMAKE_CURRENT_LIST_DIR}/antlr4/runtime/Cpp/runtime/src")
2 |
3 | file(GLOB_RECURSE ANTLR_SOURCES
4 | ${CPP_RUNTIME_PATH}/*.h
5 | ${CPP_RUNTIME_PATH}/*.c
6 | ${CPP_RUNTIME_PATH}/*.hpp
7 | ${CPP_RUNTIME_PATH}/*.cpp
8 | ${CPP_RUNTIME_PATH}/*.cc
9 | ${CPP_RUNTIME_PATH}/*.hh)
10 |
11 | add_library(antlr4 STATIC
12 | ${ANTLR_SOURCES})
13 |
14 | target_include_directories(antlr4
15 | PUBLIC
16 | "${CPP_RUNTIME_PATH}"
17 | PRIVATE
18 | "${CPP_RUNTIME_PATH}/tree")
19 |
20 | target_compile_definitions(antlr4
21 | PUBLIC
22 | "-DANTLR4CPP_STATIC")
23 |
24 | target_compile_features(antlr4
25 | PUBLIC
26 | ${CXX14_FEATURES})
27 |
28 | set_target_properties(antlr4
29 | PROPERTIES
30 | FOLDER
31 | "dep")
32 |
33 | file(DOWNLOAD
34 | http://www.antlr.org/download/antlr-4.7-complete.jar
35 | ${CMAKE_BINARY_DIR}/antlr4-complete.jar
36 | SHOW_PROGRESS
37 | EXPECTED_HASH SHA512=4172eb0d72a57aaff913cafe9e1ca36d29eec7241a9c495c5bef6009e4938c6aac887c93e273c5b088e97420746a13dfc12e7fac0c9776745b101a5da66c3888)
38 |
39 | if (ANTLR_USE_PATH_JAVA)
40 | set(Java_JAVA_EXECUTABLE "java" CACHE STRING "Java")
41 | else()
42 | find_package(Java REQUIRED)
43 | endif()
44 |
--------------------------------------------------------------------------------
/dep/cotire/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include("${CMAKE_CURRENT_LIST_DIR}/cotire/CMake/cotire.cmake")
2 |
--------------------------------------------------------------------------------
/dep/fmt/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include(CheckSymbolExists)
2 | if (WIN32)
3 | check_symbol_exists(open io.h HAVE_OPEN)
4 | else ()
5 | check_symbol_exists(open fcntl.h HAVE_OPEN)
6 | endif ()
7 |
8 | set(FMT_SOURCES
9 | ${CMAKE_CURRENT_LIST_DIR}/fmt/fmt/format.cc
10 | ${CMAKE_CURRENT_LIST_DIR}/fmt/fmt/ostream.cc)
11 |
12 | if (HAVE_OPEN)
13 | set(FMT_SOURCES ${FMT_SOURCES}
14 | ${CMAKE_CURRENT_LIST_DIR}/fmt/fmt/posix.cc)
15 | endif()
16 |
17 | add_library(fmt STATIC ${FMT_SOURCES})
18 |
19 | target_include_directories(fmt
20 | PUBLIC
21 | ${CMAKE_CURRENT_LIST_DIR}/fmt)
22 |
23 | target_compile_definitions(fmt
24 | PUBLIC
25 | -DFMT_USE_VARIADIC_TEMPLATES=1
26 | -DFMT_USE_RVALUE_REFERENCES=1
27 | -DFMT_USE_DELETED_FUNCTIONS=1
28 | -DFMT_USE_USER_DEFINED_LITERALS=1
29 | -DFMT_EXCEPTIONS=0)
30 |
31 | target_compile_features(fmt
32 | PUBLIC
33 | cxx_variadic_templates
34 | cxx_rvalue_references
35 | cxx_deleted_functions
36 | cxx_constexpr
37 | cxx_user_literals)
38 |
39 | set_target_properties(fmt
40 | PROPERTIES
41 | FOLDER
42 | "dep")
43 |
--------------------------------------------------------------------------------
/dep/function2/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(function2)
2 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | doxygen/
2 | doxygen_log.txt
3 |
--------------------------------------------------------------------------------
/lang/main.swy:
--------------------------------------------------------------------------------
1 | // -
2 | /*
3 | test0() -> { }
4 | test0() -> { } // error: Name 'test0' is already declared!
5 |
6 | // -
7 | int() -> { } // error: Name 'int' is reserved already and thus it can't be used as a function name!
8 |
9 | // -
10 | test1() -> { }
11 | test1(int test1) -> { } // error: Argument name 'test1' is already taken
12 |
13 | // -
14 | test2() int test2 -> { } // error: Argument name 'test2' is already taken
15 |
16 | // -
17 | test3Var() -> { }
18 | test3() int test3Var -> { } // error: Argument name 'test3Var' is already taken
19 |
20 | // -
21 | test4(int test4Var) int test4Var -> { } // error: Argument name 'test4Var' is already taken
22 |
23 |
24 | // -
25 | test5(test5Var) -> { } // error: Sorry, only type 'int' is useable as data type at the moment, thus 'test5Var' isn't permitted :-(
26 | */
27 |
28 | /////////////////////////////
29 | some() int -> {
30 | if false {
31 | if false {
32 | // ...
33 | } else {
34 | return true;
35 | }
36 | } else {
37 | return false;
38 | }
39 | return true;
40 | }
41 |
42 | someret(int i) int -> {
43 | int other = 5;
44 | // Introduces errors for presentation
45 | int i = unknown;
46 | if i == 2 {
47 | return i;
48 | } else {
49 | return i + other;
50 | }
51 | }
52 |
53 | consume(int arg) int -> {
54 | return add(arg, 5);
55 | }
56 |
57 | main() int -> {
58 | int i = 0;
59 | if (i == 0) * 2 {
60 | return 10;
61 | }
62 |
63 | return add(5, 10);
64 | }
65 |
66 | add(int left, int right) int -> return left + right;
67 |
68 | othermain() int -> {
69 | int var1 = 0;
70 | {
71 | int var2 = 5;
72 | var1 = var2;
73 | }
74 |
75 | int var3 = var1;
76 |
77 | // int res = mainsec();
78 | return var3;
79 | }
80 |
81 | simple() int -> {
82 | int first = get<4>();
83 | int second = invoke<3>(5);
84 | int third = get<5>(5);
85 | return first + second + third;
86 | }
87 |
88 | invoke -> {
89 | invoke(int) int -> {
90 | return 0;
91 | }
92 | }
93 |
94 | get -> {
95 | meta {
96 | int somevar = minus_two(i);
97 | }
98 |
99 | meta if (somevar == 2) {
100 | get() int -> {
101 | int huhuitstwo = 2;
102 | return minus_two(huhuitstwo);
103 | }
104 | } else {
105 | get(int value) int -> {
106 | return value;
107 | }
108 | }
109 | }
110 |
111 | minus_two(int i) int -> {
112 | return i - 2;
113 | }
114 |
115 | ////////////////
116 | mainsec() int -> {
117 | int i = mytemplate<5>();
118 | return i;
119 | }
120 |
121 | mytemplate -> {
122 | someother() int -> {
123 | meta {
124 | }
125 |
126 | return 0;
127 | }
128 | meta {
129 | // TODO fix the assert
130 | callme<>();
131 |
132 | int firstcalc = huhu + 5;
133 |
134 | if firstcalc > 0 {
135 | firstcalc = 0;
136 | } else {
137 | firstcalc = 5;
138 | }
139 | }
140 | meta {
141 | int othervar = 7;
142 | }
143 |
144 | meta if firstcalc != 0 {
145 | mytemplateother(int some) int -> {
146 | if some > 5 {
147 | return some;
148 | }
149 | return 0;
150 | }
151 | }
152 | mytemplate() int -> {
153 | return 0;
154 | }
155 | }
156 |
157 | myfn() -> {
158 | callme<>();
159 | }
160 |
161 | callme<> -> { callme() -> { int somedecl = 7; } }
162 |
163 |
164 | instit() int -> {
165 | return inst<5>();
166 | }
167 |
168 | contribute() int -> {
169 | return 30;
170 | }
171 |
172 | inst -> {
173 | meta {
174 | int hey_from_global = param;
175 |
176 | if param != 5 {
177 | hey_from_global = (hey_from_global + 5);
178 | }
179 |
180 | }
181 | inst() int -> {
182 | meta {
183 | int hey_from_local = 15;
184 |
185 | hey_from_local = (hey_from_local + 10);
186 | }
187 | meta if param != 5 {
188 | int contributed = 5;
189 | } else {
190 | int contributed = contribute();
191 | }
192 |
193 | return hey_from_global + hey_from_local + contributed;
194 | }
195 | }
196 |
197 | // inkscape
198 |
199 | somemethod() int -> {
200 | int i1 = myinst<5>();
201 | int i2 = myinst<50>();
202 | return i1 + i2;
203 | }
204 |
205 | myinst -> {
206 | meta {
207 | int param_mul_two = (param * 2);
208 | int param_mul_eight = (param_mul_two * 2);
209 | }
210 | other() int -> {
211 | return 0;
212 | }
213 | voidfn() -> {
214 | }
215 | myinst() int -> {
216 | meta if param_mul_two == 10 {
217 | voidfn();
218 | return param_mul_two;
219 | } else {
220 | int huhu1234 = other();
221 | return param + huhu1234;
222 | }
223 | }
224 | }
225 |
226 | // grammarly
227 |
--------------------------------------------------------------------------------
/src/AST/AST.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "AST.hpp"
19 |
20 | #include "ASTPredicate.hpp"
21 | #include "ASTTraversal.hpp"
22 |
23 | bool NamedDeclContext::isFunctionDecl() const {
24 | return llvm::isa(getDeclaringNode());
25 | }
26 |
27 | bool NamedDeclContext::isVarDecl() const {
28 | auto node = getDeclaringNode();
29 | return llvm::isa(node) ||
30 | llvm::isa(node);
31 | }
32 |
33 | /// Returns true when the declaration is a meta decl
34 | bool NamedDeclContext::isMetaDecl() const {
35 | return llvm::isa(getDeclaringNode());
36 | }
37 |
38 | bool NamedDeclContext::isGlobalConstant() const {
39 | return llvm::isa(getDeclaringNode());
40 | }
41 |
42 | llvm::SmallVector FunctionDeclASTNode::children() {
43 | llvm::SmallVector seq;
44 | seq.push_back(*arguments_);
45 | if (returnType_) {
46 | seq.push_back(*returnType_);
47 | }
48 | seq.push_back(body_);
49 | return seq;
50 | }
51 |
52 | llvm::SmallVector FunctionDeclASTNode::children() const {
53 | llvm::SmallVector seq;
54 | seq.push_back(*arguments_);
55 | if (returnType_) {
56 | seq.push_back(*returnType_);
57 | }
58 | seq.push_back(body_);
59 | return seq;
60 | }
61 |
62 | std::array ExpressionStmtASTNode::children() {
63 | return {{*expression_}};
64 | }
65 |
66 | std::array ExpressionStmtASTNode::children() const {
67 | return {{*expression_}};
68 | }
69 |
70 | std::array MetaDeclASTNode::children() {
71 | return {{*arguments_, *contribution_}};
72 | }
73 |
74 | std::array MetaDeclASTNode::children() const {
75 | return {{*arguments_, *contribution_}};
76 | }
77 |
78 | std::array MetaCalculationStmtASTNode::children() {
79 | return {{*stmt_}};
80 | }
81 |
82 | std::array MetaCalculationStmtASTNode::children() const {
83 | return {{*stmt_}};
84 | }
85 |
86 | std::array BinaryOperatorExprASTNode::children() {
87 | return {{*left_, *right_}};
88 | }
89 |
90 | std::array BinaryOperatorExprASTNode::children() const {
91 | return {{*left_, *right_}};
92 | }
93 |
94 | std::array DeclStmtASTNode::children() {
95 | return {{*expression_}};
96 | }
97 |
98 | std::array DeclStmtASTNode::children() const {
99 | return {{*expression_}};
100 | }
101 |
102 | ASTChildSequence CallOperatorExprASTNode::children() {
103 | ASTChildSequence seq{*callee_};
104 | seq.append(expressions_.begin(), expressions_.end());
105 | return seq;
106 | }
107 |
108 | ConstASTChildSequence CallOperatorExprASTNode::children() const {
109 | ConstASTChildSequence seq{*callee_};
110 | seq.append(expressions_.begin(), expressions_.end());
111 | return seq;
112 | }
113 |
114 | llvm::SmallVector MetaInstantiationExprASTNode::children() {
115 | llvm::SmallVector seq{*decl_};
116 | seq.append(arguments_.begin(), arguments_.end());
117 | return seq;
118 | }
119 |
120 | llvm::SmallVector
121 | MetaInstantiationExprASTNode::children() const {
122 | llvm::SmallVector seq{*decl_};
123 | seq.append(arguments_.begin(), arguments_.end());
124 | return seq;
125 | }
126 |
127 | bool StmtASTNode::classof(ASTNode const* node) {
128 | return traverseNode(node, decorate(identityOf(), pred::isStmtNode()));
129 | }
130 |
131 | bool ExprASTNode::classof(ASTNode const* node) {
132 | return traverseNode(node, decorate(identityOf(), pred::isExprNode()));
133 | }
134 |
--------------------------------------------------------------------------------
/src/AST/AST.inl:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef FOR_EACH_AST_NODE
19 | #define FOR_EACH_AST_NODE(NAME)
20 | #endif
21 |
22 | #ifndef FOR_EACH_STMT_NODE
23 | #define FOR_EACH_STMT_NODE(NAME) FOR_EACH_AST_NODE(NAME)
24 | #endif
25 |
26 | #ifndef FOR_EACH_EXPR_NODE
27 | #define FOR_EACH_EXPR_NODE(NAME) FOR_EACH_AST_NODE(NAME)
28 | #endif
29 |
30 | FOR_EACH_AST_NODE(CompilationUnit)
31 | FOR_EACH_AST_NODE(MetaUnit)
32 | FOR_EACH_AST_NODE(FunctionDecl)
33 | FOR_EACH_AST_NODE(MetaDecl)
34 | FOR_EACH_AST_NODE(MetaContribution)
35 | FOR_EACH_AST_NODE(ArgumentDeclList)
36 | FOR_EACH_AST_NODE(AnonymousArgumentDecl)
37 | FOR_EACH_AST_NODE(NamedArgumentDecl)
38 | FOR_EACH_AST_NODE(GlobalConstantDecl)
39 |
40 | FOR_EACH_STMT_NODE(UnscopedCompoundStmt)
41 | FOR_EACH_STMT_NODE(CompoundStmt)
42 | FOR_EACH_STMT_NODE(ReturnStmt)
43 | FOR_EACH_STMT_NODE(ExpressionStmt)
44 | FOR_EACH_STMT_NODE(DeclStmt)
45 | FOR_EACH_STMT_NODE(IfStmt)
46 | FOR_EACH_STMT_NODE(MetaIfStmt)
47 | FOR_EACH_STMT_NODE(MetaCalculationStmt)
48 |
49 | FOR_EACH_EXPR_NODE(DeclRefExpr)
50 | FOR_EACH_EXPR_NODE(IntegerLiteralExpr)
51 | FOR_EACH_EXPR_NODE(BooleanLiteralExpr)
52 | FOR_EACH_EXPR_NODE(ErroneousExpr)
53 | FOR_EACH_EXPR_NODE(BinaryOperatorExpr)
54 | FOR_EACH_EXPR_NODE(CallOperatorExpr)
55 | FOR_EACH_EXPR_NODE(MetaInstantiationExpr)
56 |
57 | #undef FOR_EACH_EXPR_NODE
58 | #undef FOR_EACH_STMT_NODE
59 | #undef FOR_EACH_AST_NODE
60 |
61 |
62 | #ifndef EXPR_BINARY_OPERATOR
63 | #define EXPR_BINARY_OPERATOR(NAME, REP, PRECEDENCE)
64 | #endif
65 |
66 | EXPR_BINARY_OPERATOR(Mul, "*", 50)
67 | EXPR_BINARY_OPERATOR(Div, "/", 50)
68 | EXPR_BINARY_OPERATOR(Plus, "+", 40)
69 | EXPR_BINARY_OPERATOR(Minus, "-", 40)
70 | EXPR_BINARY_OPERATOR(LessThan, "<", 30)
71 | EXPR_BINARY_OPERATOR(GreaterThan, ">", 30)
72 | EXPR_BINARY_OPERATOR(LessThanOrEq, "<=", 30)
73 | EXPR_BINARY_OPERATOR(GreaterThanOrEq, ">=", 30)
74 | EXPR_BINARY_OPERATOR(Equal, "==", 20)
75 | EXPR_BINARY_OPERATOR(NotEqual, "!=", 20)
76 | EXPR_BINARY_OPERATOR(Assign, "=", 10)
77 |
78 | #undef EXPR_BINARY_OPERATOR
79 |
--------------------------------------------------------------------------------
/src/AST/ASTCloner.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "ASTCloner.hpp"
19 |
20 | #include "llvm/Support/Casting.h"
21 |
22 | #include "AST.hpp"
23 | #include "ASTTraversal.hpp"
24 |
25 | ASTNode* ASTCloner::clone(ASTNode const* node) {
26 | switch (node->getKind()) {
27 | #define FOR_EACH_AST_NODE(NAME) \
28 | case ASTKind::Kind##NAME: \
29 | return clone##NAME(llvm::cast(node));
30 | #include "AST.inl"
31 | default:
32 | llvm_unreachable("Unknown node type!");
33 | }
34 | }
35 |
36 | CompilationUnitASTNode*
37 | ASTCloner::cloneCompilationUnit(CompilationUnitASTNode const* /*node*/) {
38 | return allocate();
39 | }
40 |
41 | MetaUnitASTNode* ASTCloner::cloneMetaUnit(MetaUnitASTNode const* node) {
42 | return allocate(node->getInstantiation());
43 | }
44 |
45 | FunctionDeclASTNode*
46 | ASTCloner::cloneFunctionDecl(FunctionDeclASTNode const* node) {
47 | return allocate(relocate(node->getName()));
48 | }
49 |
50 | MetaDeclASTNode* ASTCloner::cloneMetaDecl(MetaDeclASTNode const* node) {
51 | return allocate(node->getName());
52 | }
53 |
54 | GlobalConstantDeclASTNode*
55 | ASTCloner::cloneGlobalConstantDecl(GlobalConstantDeclASTNode const* node) {
56 | return allocate(node->getName());
57 | }
58 |
59 | MetaContributionASTNode*
60 | ASTCloner::cloneMetaContribution(MetaContributionASTNode const* node) {
61 | return allocate(relocate(node->getSourceRange()));
62 | }
63 |
64 | MetaInstantiationExprASTNode* ASTCloner::cloneMetaInstantiationExpr(
65 | MetaInstantiationExprASTNode const* node) {
66 | return allocate(
67 | relocate(node->getSourceRange()));
68 | }
69 |
70 | ArgumentDeclListASTNode*
71 | ASTCloner::cloneArgumentDeclList(ArgumentDeclListASTNode const* /*node*/) {
72 | return allocate();
73 | }
74 |
75 | AnonymousArgumentDeclASTNode* ASTCloner::cloneAnonymousArgumentDecl(
76 | AnonymousArgumentDeclASTNode const* /*node*/) {
77 | return allocate();
78 | }
79 |
80 | NamedArgumentDeclASTNode*
81 | ASTCloner::cloneNamedArgumentDecl(NamedArgumentDeclASTNode const* node) {
82 | return allocate(relocate(node->getName()));
83 | }
84 |
85 | UnscopedCompoundStmtASTNode* ASTCloner::cloneUnscopedCompoundStmt(
86 | UnscopedCompoundStmtASTNode const* /*node*/) {
87 | return allocate();
88 | }
89 |
90 | CompoundStmtASTNode*
91 | ASTCloner::cloneCompoundStmt(CompoundStmtASTNode const* /*node*/) {
92 | return allocate();
93 | }
94 |
95 | ReturnStmtASTNode*
96 | ASTCloner::cloneReturnStmt(ReturnStmtASTNode const* /*node*/) {
97 | return allocate();
98 | }
99 |
100 | ExpressionStmtASTNode*
101 | ASTCloner::cloneExpressionStmt(ExpressionStmtASTNode const* /*node*/) {
102 | return allocate();
103 | }
104 |
105 | DeclStmtASTNode* ASTCloner::cloneDeclStmt(DeclStmtASTNode const* node) {
106 | return allocate(relocate(node->getName()));
107 | }
108 |
109 | IfStmtASTNode* ASTCloner::cloneIfStmt(IfStmtASTNode const* /*node*/) {
110 | return allocate();
111 | }
112 |
113 | MetaIfStmtASTNode*
114 | ASTCloner::cloneMetaIfStmt(MetaIfStmtASTNode const* /*node*/) {
115 | return allocate();
116 | }
117 |
118 | MetaCalculationStmtASTNode* ASTCloner::cloneMetaCalculationStmt(
119 | MetaCalculationStmtASTNode const* /*node*/) {
120 | return allocate();
121 | }
122 |
123 | DeclRefExprASTNode*
124 | ASTCloner::cloneDeclRefExpr(DeclRefExprASTNode const* node) {
125 | return allocate(relocate(node->getName()));
126 | }
127 |
128 | IntegerLiteralExprASTNode*
129 | ASTCloner::cloneIntegerLiteralExpr(IntegerLiteralExprASTNode const* node) {
130 | return allocate(relocate(node->getLiteral()));
131 | }
132 |
133 | BooleanLiteralExprASTNode*
134 | ASTCloner::cloneBooleanLiteralExpr(BooleanLiteralExprASTNode const* node) {
135 | return allocate(relocate(node->getLiteral()));
136 | }
137 |
138 | ErroneousExprASTNode*
139 | ASTCloner::cloneErroneousExpr(ErroneousExprASTNode const* /*node*/) {
140 | return allocate();
141 | }
142 |
143 | BinaryOperatorExprASTNode*
144 | ASTCloner::cloneBinaryOperatorExpr(BinaryOperatorExprASTNode const* node) {
145 | return allocate(
146 | relocate(node->getBinaryOperator()));
147 | }
148 |
149 | CallOperatorExprASTNode*
150 | ASTCloner::cloneCallOperatorExpr(CallOperatorExprASTNode const* /*node*/) {
151 | return allocate();
152 | }
153 |
--------------------------------------------------------------------------------
/src/AST/ASTCloner.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_CLONER_HPP_INCLUDED__
19 | #define AST_CLONER_HPP_INCLUDED__
20 |
21 | #include "ASTContext.hpp"
22 | #include "SourceAnnotated.hpp"
23 | #include "SourceLocation.hpp"
24 |
25 | class ASTNode;
26 | #define FOR_EACH_AST_NODE(NAME) class NAME##ASTNode;
27 | #include "AST.inl"
28 |
29 | /// The SourceRelocator provides methods for relocating the source location
30 | /// of cloned ASTNodes properties.
31 | class SourceRelocator {
32 | public:
33 | SourceRelocator() = default;
34 | virtual ~SourceRelocator() = default;
35 |
36 | /// Relocates the given SourceLocation
37 | virtual SourceLocation relocate(SourceLocation const& loc) { return loc; }
38 | /// Relocates the given SourceRange
39 | virtual SourceRange relocate(SourceRange const& range) { return range; }
40 | /// Relocates the given SourceAnnotated
41 | template ::value ||
44 | std::is_same::value>>
45 | SourceAnnotated
46 | relocate(SourceAnnotated const& annotated) {
47 | return {*annotated, relocate(annotated.getAnnotation())};
48 | }
49 | };
50 |
51 | /// Provides methods for cloning an ASTNode itself without it's children.
52 | ///
53 | /// A whole subtree can be cloned through invoking the cloner
54 | /// together with the ASTLayoutReader.
55 | class ASTCloner {
56 | ASTContext* context_;
57 | SourceRelocator* relocator_;
58 |
59 | public:
60 | ASTCloner(ASTContext* context, SourceRelocator* relocator)
61 | : context_(context), relocator_(relocator) {}
62 |
63 | /// Clones the given node without it's children
64 | ASTNode* clone(ASTNode const* node);
65 | /// Provide clone methods for all types of ASTNode's
66 | #define FOR_EACH_AST_NODE(NAME) \
67 | NAME##ASTNode* clone##NAME(NAME##ASTNode const* node);
68 | #include "AST.inl"
69 |
70 | private:
71 | /// Forwards to ASTContext::allocate
72 | template T* allocate(Args&&... args) {
73 | return context_->allocate(std::forward(args)...);
74 | }
75 | /// Relocates the given SourceLocation
76 | template auto relocate(T&& type) {
77 | return relocator_->relocate(std::forward(type));
78 | }
79 | };
80 |
81 | #endif // #ifndef AST_CLONER_HPP_INCLUDED__
82 |
--------------------------------------------------------------------------------
/src/AST/ASTContext.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "ASTContext.hpp"
19 |
20 | #include "AST.hpp"
21 |
22 | ASTContext::~ASTContext() {
23 | // Call the destructor for all allocated AST nodes
24 | for (auto allocated : allocated_) {
25 | allocated->~ASTFragment();
26 | }
27 | }
28 |
29 | llvm::StringRef ASTContext::poolString(llvm::StringRef str) {
30 | auto itr = stringPool_.find(str);
31 | if (itr != stringPool_.end()) {
32 | return *itr;
33 | }
34 | auto const size = str.size();
35 | auto* rep = static_cast(allocator_.Allocate(size, alignof(char)));
36 |
37 | for (std::size_t i = 0; i < size; ++i) {
38 | rep[i] = str[i];
39 | }
40 | llvm::StringRef ref(rep, size);
41 | stringPool_.insert(ref);
42 | return ref;
43 | }
44 |
--------------------------------------------------------------------------------
/src/AST/ASTContext.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_CONTEXT_HPP_INCLUDED__
19 | #define AST_CONTEXT_HPP_INCLUDED__
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "llvm/ADT/StringRef.h"
27 | #include "llvm/Support/Allocator.h"
28 |
29 | #include "ASTFragment.hpp"
30 | #include "ASTPredicate.hpp"
31 | #include "Hash.hpp"
32 | #include "Traits.hpp"
33 |
34 | class ASTNode;
35 |
36 | /// Represents the context of an abstract syntax tree
37 | ///
38 | /// Contains the allocated memory for it and also keeps
39 | /// fragments that aren't part of the AST accessible.
40 | class ASTContext {
41 | llvm::BumpPtrAllocator allocator_;
42 | std::deque allocated_;
43 |
44 | // We can ensure that all strings are needed due to the lifetime
45 | // of this context so we don't need a reference counted pool
46 | // like llvm::StringPool.
47 | std::unordered_set stringPool_;
48 |
49 | public:
50 | ASTContext() = default;
51 | ~ASTContext();
52 |
53 | /// Allocates an ASTNode object of the given type inside the ASTContext.
54 | /// The object automatically gets destructed aside with the ASTContext,
55 | /// making it unnecessary to manage it's memory.
56 | template T* allocate(Args&&... args) {
57 | static_assert(std::is_base_of::value,
58 | "Can only allocate ASTFragment's!");
59 | T* allocated = static_cast(allocator_.Allocate(sizeof(T), alignof(T)));
60 | new (allocated) T(std::forward(args)...);
61 | staticIf(allocated, pred::isNotTrivialDestructible(),
62 | [&](ASTFragment* fragment) { allocated_.push_back(fragment); });
63 | return allocated;
64 | }
65 |
66 | /// Pools the string into the internal string table
67 | llvm::StringRef poolString(llvm::StringRef str);
68 | };
69 |
70 | /// Represents a shared instance of an ASTContext
71 | using ASTContextRef = std::shared_ptr;
72 |
73 | #endif // #ifndef AST_CONTEXT_HPP_INCLUDED__
74 |
--------------------------------------------------------------------------------
/src/AST/ASTCursor.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "ASTCursor.hpp"
19 |
20 | #include
21 |
22 | #include "AST.hpp"
23 |
24 | /*
25 | bool operator==(ASTCursor const& other) const {
26 | return is(other.depth_, metaDepth_);
27 | }
28 | bool operator!=(ASTCursor const& other) const { return !(*this == other); }
29 |
30 | bool operator==(DepthLevel level) const { return is(level); }
31 | bool operator<(DepthLevel level) const { return depth_ < level; }
32 | bool operator<=(DepthLevel level) const { return depth_ <= level; }
33 | bool operator>(DepthLevel level) const { return depth_ > level; }
34 | bool operator>=(DepthLevel level) const { return depth_ >= level; }
35 |
36 | bool operator==(MetaDepthLevel level) const { return is(level); }
37 | bool operator<(MetaDepthLevel level) const { return metaDepth_ < level; }
38 | bool operator<=(MetaDepthLevel level) const { return metaDepth_ <= level; }
39 | bool operator>(MetaDepthLevel level) const { return metaDepth_ > level; }
40 | bool operator>=(MetaDepthLevel level) const { return metaDepth_ >= level; }
41 | */
42 |
43 | template void transitionDepth(ASTKind kind, T&& apply) {
44 | switch (kind) {
45 | case ASTKind::KindFunctionDecl:
46 | // FunctionDeclASTNode: TopLevel -> InsideFunctionDecl
47 | std::forward(apply)(DepthLevel::TopLevel,
48 | DepthLevel::InsideFunctionDecl);
49 | break;
50 | default:
51 | break;
52 | }
53 | }
54 |
55 | template void transitionMetaDepth(ASTKind kind, T&& apply) {
56 | switch (kind) {
57 | case ASTKind::KindMetaDecl:
58 | // MetaDeclASTNode: Outside -> Inside
59 | std::forward(apply)(MetaDepthLevel::Outside,
60 | MetaDepthLevel::InsideMetaDecl);
61 | break;
62 | case ASTKind::KindMetaCalculationStmt:
63 | // MetaCalculationStmtASTNode: Inside -> InsideComputation
64 | std::forward(apply)(MetaDepthLevel::InsideMetaDecl,
65 | MetaDepthLevel::InsideComputation);
66 | break;
67 | default:
68 | break;
69 | }
70 | }
71 |
72 | template auto makeTransition(ASTDepth* depth) {
73 | return [=](auto from, auto to) {
74 | assert(depth->is(from) && "Unbalanced transitioning!");
75 | depth->set(to);
76 | };
77 | }
78 |
79 | /// Passes the arguments in reversed order into the given functor
80 | template auto reverse(T&& apply) {
81 | return [apply = std::forward(apply)](auto left, auto right) {
82 | return apply(right, left);
83 | };
84 | }
85 |
86 | template <> void ASTDepth::descend(ASTKind kind) {
87 | transitionDepth(kind, makeTransition(this));
88 | }
89 |
90 | template <> void ASTDepth::ascend(ASTKind kind) {
91 | transitionDepth(kind, reverse(makeTransition(this)));
92 | }
93 |
94 | template <> void ASTDepth::descend(ASTKind kind) {
95 | transitionMetaDepth(kind, makeTransition(this));
96 | }
97 |
98 | template <> void ASTDepth::ascend(ASTKind kind) {
99 | transitionMetaDepth(kind, reverse(makeTransition(this)));
100 | }
101 |
102 | template class ASTDepth;
103 | template class ASTDepth;
104 |
105 | void ASTCursor::descend(ASTKind kind) {
106 | ASTDepth::descend(kind);
107 | ASTDepth::descend(kind);
108 | }
109 |
110 | void ASTCursor::ascend(ASTKind kind) {
111 | ASTDepth::ascend(kind);
112 | ASTDepth::ascend(kind);
113 | }
114 |
--------------------------------------------------------------------------------
/src/AST/ASTCursor.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 | #ifndef AST_CURSOR_HPP_INCLUDED__
18 | #define AST_CURSOR_HPP_INCLUDED__
19 |
20 | #include
21 |
22 | class ASTNode;
23 | enum class ASTKind;
24 |
25 | /// Describes the depth on how far we descended in the AST level
26 | enum class DepthLevel {
27 | /// We are on the top level scope, which is part of a UnitASTNode.
28 | /// Node we are faced with should inherit the TopLevelASTNode.
29 | TopLevel,
30 | /// We are inside a function declaration which means all nodes are
31 | /// transitive children of FunctionDeclASTNode.
32 | InsideFunctionDecl
33 | };
34 |
35 | /// Describes the depth on how far we descended in the meta level
36 | enum class MetaDepthLevel {
37 | /// We are in no MetaDeclASTNode which is equivalent
38 | /// to the the default state.
39 | Outside,
40 | /// We are inside a MetaDeclASTNode and contributing the nodes
41 | /// to the instantiation.
42 | InsideMetaDecl,
43 | /// We are inside a meta computation and doing compile-time computations.
44 | /// Children aren't contributed to the instantiation anymore.
45 | InsideComputation
46 | };
47 |
48 | /// Represents a 1 dimensional depth in the AST
49 | template class ASTDepth {
50 | T depth_{};
51 |
52 | public:
53 | ASTDepth() = default;
54 | explicit ASTDepth(T depth) : depth_(std::move(depth)) {}
55 |
56 | /// Returns true when we are in the given depth
57 | bool is(T depth) const { return depth_ == depth; }
58 | /// Returns the current depth
59 | T const& get() const { return depth_; }
60 | /// Sets the current depth
61 | void set(T depth) { depth_ = std::move(depth); }
62 |
63 | /// Descends into the AST which means we are increasing the depth level
64 | void descend(ASTKind kind);
65 | /// Ascend from the AST which means we are decreasing the depth level
66 | void ascend(ASTKind kind);
67 | };
68 |
69 | /// Represents a 2 dimensional cursor which tracks the AST and meta depth
70 | class ASTCursor : protected ASTDepth,
71 | protected ASTDepth {
72 | public:
73 | explicit ASTCursor(DepthLevel depth = DepthLevel{},
74 | MetaDepthLevel metaDepth = MetaDepthLevel{})
75 | : ASTDepth(depth), ASTDepth(metaDepth) {}
76 |
77 | /*bool is(DepthLevel level) const { return depth_ == level; }
78 | bool is(MetaDepthLevel level) const { return metaDepth_ == level; }*/
79 | bool is(DepthLevel depthLevel, MetaDepthLevel metaDepthLevel) const {
80 | return ASTDepth::is(depthLevel) &&
81 | ASTDepth::is(metaDepthLevel);
82 | }
83 |
84 | /// Returns the current depth
85 | DepthLevel getDepth() const { return ASTDepth::get(); }
86 | /// Returns the current meta depth
87 | MetaDepthLevel getMetaDepth() const {
88 | return ASTDepth::get();
89 | }
90 |
91 | /// Descends into the AST which means we are increasing the depth level
92 | void descend(ASTKind kind);
93 | /// Ascend from the AST which means we are decreasing the depth level
94 | void ascend(ASTKind kind);
95 |
96 | /// Returns true when the cursor points into a function decl
97 | bool isInsideFunctionDecl() const {
98 | return ASTDepth::get() >= DepthLevel::InsideFunctionDecl;
99 | }
100 | /// Returns true when the cursor points into a meta decl
101 | bool isInsideMetaDecl() const {
102 | return ASTDepth::get() >= MetaDepthLevel::InsideMetaDecl;
103 | }
104 | };
105 |
106 | #endif // #ifndef AST_CURSOR_HPP_INCLUDED__
107 |
--------------------------------------------------------------------------------
/src/AST/ASTFragment.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_FRAGMENT_HPP_INCLUDED__
19 | #define AST_FRAGMENT_HPP_INCLUDED__
20 |
21 | /// Represents an ASTFragment which is managed in by it's
22 | /// corresponding ASTContext.
23 | class ASTFragment {
24 | public:
25 | ASTFragment() = default;
26 | virtual ~ASTFragment() = default;
27 | };
28 |
29 | /// Represents an intermediate node which must not passed to any codegen
30 | class IntermediateNode {
31 | public:
32 | IntermediateNode() = default;
33 | ~IntermediateNode() = default;
34 | };
35 |
36 | #endif // #ifndef AST_FRAGMENT_HPP_INCLUDED__
37 |
--------------------------------------------------------------------------------
/src/AST/ASTPredicate.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_PREDICATE_HPP_INCLUDED__
19 | #define AST_PREDICATE_HPP_INCLUDED__
20 |
21 | #include
22 |
23 | #include "AST.hpp"
24 | #include "Traits.hpp"
25 |
26 | /// The namespace `pred` provides compile-time predicates for ASTNode's
27 | namespace pred {
28 | /// A static AST predicate which returns a true type:
29 | /// - if the node provides a 'children()' method for iterating it's children.
30 | inline auto hasChildren() {
31 | return validatorOf(
32 | [](auto* checked) -> decltype((void)checked->children()) {});
33 | }
34 |
35 | namespace detail {
36 | template
37 | struct known_size_of : std::integral_constant {};
38 |
39 | template
40 | struct known_size_of>
41 | : std::integral_constant {};
42 |
43 | /// Returns a functor which tests it argument type with the given trait
44 | template class T> inline auto applyTrait() {
45 | return [](auto node) {
46 | (void)node;
47 | return T>{};
48 | };
49 | }
50 |
51 | /// Returns a functor which tests it argument type with the given trait
52 | /// and the curried argument.
53 | template class T, typename FirstArg>
54 | inline auto applyTrait() {
55 | return [](auto node) {
56 | (void)node;
57 | return T>{};
58 | };
59 | }
60 | } // end namespace detail
61 |
62 | /// A static AST predicate which returns an integral constant:
63 | /// - which indicates the known fixed size of a nodes children,
64 | /// 0 if the node has a dynamic size of children.
65 | inline auto getKnownAmountOfChildren() {
66 | return [](auto* checked) {
67 | (void)checked;
68 | return detail::known_size_ofchildren())>>{};
69 | };
70 | }
71 |
72 | /// A static AST predicate which returns a true type:
73 | /// - if the node provides a variable size of children
74 | inline auto hasUnknownAmountOfChildren() {
75 | return [](auto* checked) {
76 | auto known = getKnownAmountOfChildren()(checked);
77 | (void)known;
78 | return std::integral_constant{};
79 | };
80 | }
81 |
82 | /// A static AST predicate which returns a true type:
83 | /// - if the node requires a reduce marker
84 | inline auto isRequiringReduceMarker() {
85 | return [](auto checked) {
86 | return conditionalEvaluate(hasChildren()(checked), checked,
87 | hasUnknownAmountOfChildren(),
88 | supplierOf());
89 | };
90 | }
91 |
92 | /// A static AST predicate which returns a true type:
93 | /// - if the node is a base of the given type.
94 | template inline auto isBaseOf(identity = {}) {
95 | return detail::applyTrait();
96 | }
97 |
98 | /// A static AST predicate which returns a true type:
99 | /// - if the node is a NamedDeclContext.
100 | inline auto isNamedDeclContext() { return isBaseOf(); }
101 |
102 | /// A static AST predicate which returns a true type:
103 | /// - if the node is a top level ASTNode
104 | inline auto isTopLevelNode() { return isBaseOf(); };
105 |
106 | /// A static AST predicate which returns a true type:
107 | /// - if the node is a unit node
108 | inline auto isUnitNode() { return isBaseOf(); };
109 |
110 | /// A static AST predicate which returns a true type:
111 | /// - if the node is a StmtASTNode
112 | inline auto isStmtNode() { return isBaseOf(); };
113 |
114 | /// A static AST predicate which returns a true type:
115 | /// - if the node is a ExprASTNode
116 | inline auto isExprNode() { return isBaseOf(); };
117 |
118 | /// A static AST predicate which returns a true type:
119 | /// - if the node is a top level decl context
120 | inline auto isTopLevelDeclContextNode() {
121 | return [](auto node) {
122 | return isNamedDeclContext()(node) && isTopLevelNode()(node);
123 | };
124 | }
125 |
126 | /// A static AST predicate which returns a true type:
127 | /// - if the node is the the same as the given ASTNode
128 | template auto isSameAs(identity = {}) {
129 | return detail::applyTrait();
130 | }
131 |
132 | /// A static AST predicate which returns a true type:
133 | /// - if the argument node is any of the given ones.
134 | template auto isAnyNodeOf(T... nodes) {
135 | return [=](auto matchable) {
136 | return isAnyOf(plainify(identityOf(matchable)), identityOf(nodes)...);
137 | };
138 | }
139 |
140 | /// A static AST predicate which returns a true type:
141 | /// - if the node is not trivially destructible
142 | inline auto isNotTrivialDestructible() {
143 | return [](auto const* node) {
144 | (void)node;
145 | return std::integral_constant>::value>{};
147 | };
148 | }
149 | } // end namespace pred
150 |
151 | #endif // #ifndef AST_PREDICATE_HPP_INCLUDED__
152 |
--------------------------------------------------------------------------------
/src/AST/ASTScope.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "ASTScope.hpp"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | // #include "llvm/ADT/StringMap.h"
25 | #include "Hash.hpp"
26 |
27 | #include "AST.hpp"
28 | #include "ASTContext.hpp"
29 |
30 | template
31 | class AllocatedScope : public Current {
32 | llvm::Optional parent_;
33 | std::unordered_map
34 | lookupMap_;
35 |
36 | static unsigned const THRESHOLD = 10U;
37 |
38 | public:
39 | explicit AllocatedScope(llvm::Optional parent)
40 | : parent_(parent) {
41 | assert((!parent.hasValue() || *parent) &&
42 | "Parent isn't allowed to be null!");
43 | }
44 |
45 | llvm::Optional parent() const override {
46 | if (parent_)
47 | return llvm::Optional(*parent_);
48 | else
49 | return llvm::Optional();
50 | }
51 |
52 | void insert(llvm::StringRef str, NamedDeclContext* node) override {
53 | assert(!lookupMap_.count(str) &&
54 | "The entry should never exists in the same scope");
55 | lookupMap_.insert(std::make_pair(str, node));
56 | }
57 |
58 | Nullable
59 | lookupIdentifier(llvm::StringRef str) const override {
60 | auto itr = lookupMap_.find(str);
61 | if (itr != lookupMap_.end())
62 | return itr->second;
63 | else if (parent_)
64 | return (*parent_)->lookupIdentifier(str);
65 | else
66 | return nullptr;
67 | }
68 |
69 | bool isConsistent() const override { return IsConsistent; }
70 |
71 | Nullable similarTo(llvm::StringRef str) const override {
72 | return similarTo(str, THRESHOLD, nullptr);
73 | }
74 |
75 | Nullable
76 | similarTo(llvm::StringRef str, unsigned distance,
77 | NamedDeclContext* current) const override {
78 | // Calculate the local most similar declaration
79 | {
80 | NamedDeclContext* myCurrent;
81 | unsigned myDistance;
82 | std::tie(myCurrent, myDistance) = myMostSimilarString(str);
83 |
84 | if (myDistance < distance) {
85 | distance = myDistance;
86 | current = myCurrent;
87 | }
88 | }
89 |
90 | if (parent_)
91 | return (*parent_)->similarTo(str, distance, current);
92 | else
93 | return current;
94 | }
95 |
96 | private:
97 | std::tuple
98 | myMostSimilarString(llvm::StringRef str) const {
99 | NamedDeclContext* myMostSimilarContext = nullptr;
100 | auto myMostSimilarValue = THRESHOLD;
101 |
102 | for (auto const& entry : lookupMap_) {
103 | auto similarity = str.edit_distance(entry.first, true, THRESHOLD);
104 |
105 | if (similarity < myMostSimilarValue) {
106 | myMostSimilarContext = entry.second;
107 | myMostSimilarValue = similarity;
108 | }
109 | }
110 |
111 | return std::make_tuple(myMostSimilarContext, myMostSimilarValue);
112 | }
113 | };
114 |
115 | std::unique_ptr
116 | ASTScope::CreateTemporary(llvm::Optional parent) {
117 | return std::make_unique>(parent);
118 | }
119 |
120 | ConsistentASTScope* ConsistentASTScope::CreateConsistent(
121 | ASTContext* astContext,
122 | llvm::Optional parent /*= llvm::None*/) {
123 | // TODO Also allocate scoped entries through the ASTContext allocator
124 | return astContext->allocate>(parent);
125 | }
126 |
127 | class InplaceASTScopeImpl : public InplaceASTScope {
128 | ASTScope* parent_;
129 | ListenerType listener_;
130 |
131 | public:
132 | InplaceASTScopeImpl(ASTScope* parent,
133 | llvm::function_ref listener)
134 | : parent_(parent), listener_(listener) {}
135 |
136 | llvm::Optional parent() const override {
137 | return parent_->parent();
138 | }
139 | void insert(llvm::StringRef str, NamedDeclContext* node) override {
140 | parent_->insert(str, node);
141 | listener_(node);
142 | }
143 | Nullable
144 | lookupIdentifier(llvm::StringRef str) const override {
145 | return parent_->lookupIdentifier(str);
146 | }
147 | bool isConsistent() const override { return parent_->isConsistent(); }
148 | Nullable similarTo(llvm::StringRef str) const override {
149 | return parent_->similarTo(str);
150 | }
151 | Nullable
152 | similarTo(llvm::StringRef str, unsigned distance,
153 | NamedDeclContext* current) const override {
154 | return parent_->similarTo(str, distance, current);
155 | }
156 | };
157 |
158 | std::unique_ptr
159 | InplaceASTScope::CreateInplace(ASTScope* parent, ListenerType listener) {
160 | return std::make_unique(parent, listener);
161 | }
162 |
--------------------------------------------------------------------------------
/src/AST/ASTScope.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_SCOPE_HPP_INCLUDED__
19 | #define AST_SCOPE_HPP_INCLUDED__
20 |
21 | #include
22 |
23 | #include "llvm/ADT/Optional.h"
24 | #include "llvm/ADT/STLExtras.h"
25 | #include "llvm/ADT/StringRef.h"
26 |
27 | #include "ASTFragment.hpp"
28 | #include "Nullable.hpp"
29 |
30 | class ASTContext;
31 | class NamedDeclContext;
32 |
33 | /// Represents a scoped visibility for identifiers that reference
34 | /// to an unique NamedDeclASTNode which is represented by that identifier.
35 | ///
36 | /// This class is similar to llvm::ScopedHashTable, however it provides
37 | /// support for multiple living scopes inheriting from the same scope.
38 | class ASTScope : public ASTFragment {
39 | public:
40 | ASTScope() = default;
41 | ASTScope(ASTScope&&) = delete;
42 | ASTScope& operator=(ASTScope&&) = delete;
43 |
44 | /// Returns the parent of this scope
45 | virtual llvm::Optional parent() const = 0;
46 |
47 | /// Inserts the given string into this scope
48 | virtual void insert(llvm::StringRef str, NamedDeclContext* node) = 0;
49 |
50 | /// Returns the NamedDeclASTNode visible in the current scope that is
51 | /// matching the given StringRef.
52 | virtual Nullable
53 | lookupIdentifier(llvm::StringRef str) const = 0;
54 |
55 | /// Returns true when this scope is permanent within this context
56 | virtual bool isConsistent() const = 0;
57 |
58 | /// Returns the most obvious alternative in the current
59 | /// scope to the given string
60 | virtual Nullable similarTo(llvm::StringRef str) const = 0;
61 |
62 | //// Allocates a temporary scope
63 | static std::unique_ptr
64 | CreateTemporary(llvm::Optional parent = llvm::None);
65 |
66 | virtual Nullable
67 | similarTo(llvm::StringRef str, unsigned distance,
68 | NamedDeclContext* current) const = 0;
69 | };
70 |
71 | /// Represents a consistent AST scope which is kept accessible
72 | /// within the AST for accessing global scope members.
73 | class ConsistentASTScope : public ASTScope {
74 | public:
75 | ConsistentASTScope() = default;
76 |
77 | /// Allocates a permanent scope for the given AST context
78 | static ConsistentASTScope* CreateConsistent(
79 | ASTContext* astContext,
80 | llvm::Optional parent = llvm::None);
81 | };
82 |
83 | /// Represents an inplace AST scope which doesn't introduce a new logical layer
84 | /// but provides the capability on listening on node introduces into the
85 | /// current layer.
86 | class InplaceASTScope : public ASTScope {
87 | public:
88 | using ListenerType = llvm::function_ref;
89 |
90 | InplaceASTScope() = default;
91 |
92 | /// Allocates an inplace scope for the given AST context
93 | static std::unique_ptr CreateInplace(ASTScope* parent,
94 | ListenerType listener);
95 | };
96 |
97 | #endif // #ifndef AST_SCOPE_HPP_INCLUDED__
98 |
--------------------------------------------------------------------------------
/src/AST/ASTStringer.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "ASTStringer.hpp"
19 |
20 | #include "llvm/Support/ErrorHandling.h"
21 |
22 | #include "Formatting.hpp"
23 |
24 | struct TypeStringer {
25 | #define FOR_EACH_AST_NODE(NAME) \
26 | \
27 | static llvm::StringRef \
28 | toTypeStringImpl(NAME##ASTNode const*) { \
29 | return #NAME; \
30 | \
31 | }
32 | #include "AST.inl"
33 | };
34 |
35 | llvm::StringRef ASTStringer::toTypeString(ASTNode const* node) {
36 | return traverseNode(node, [](auto promoted) {
37 | return TypeStringer::toTypeStringImpl(promoted);
38 | });
39 | }
40 |
41 | llvm::Optional
42 | ASTStringer::toStringImpl(NamedDeclContext const* decl) {
43 | return decl->getName()->str();
44 | }
45 |
46 | llvm::Optional
47 | ASTStringer::toStringImpl(DeclRefExprASTNode const* node) {
48 | if (node->isResolved()) {
49 | return fmt::format("{} ", node->getName().getType(),
50 | toTypeString(node->getDecl()->getDeclaringNode()));
51 | } else {
52 | return fmt::format("{} ", node->getName().getType());
53 | }
54 | }
55 |
56 | llvm::Optional
57 | ASTStringer::toStringImpl(IntegerLiteralExprASTNode const* node) {
58 | return std::to_string(*node->getLiteral());
59 | }
60 |
61 | llvm::Optional
62 | ASTStringer::toStringImpl(BooleanLiteralExprASTNode const* node) {
63 | return node->getLiteral() ? std::string("true") : std::string("false");
64 | }
65 |
66 | llvm::Optional
67 | ASTStringer::toStringImpl(BinaryOperatorExprASTNode const* node) {
68 | switch (*node->getBinaryOperator()) {
69 | #define EXPR_BINARY_OPERATOR(NAME, REP, ...) \
70 | case ExprBinaryOperator::Operator##NAME: \
71 | return std::string(REP);
72 | #include "AST.inl"
73 | default:
74 | llvm_unreachable("Unhandled binary expr operator!");
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/AST/ASTStringer.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_STRINGER_HPP_INCLUDED__
19 | #define AST_STRINGER_HPP_INCLUDED__
20 |
21 | #include
22 | #include
23 |
24 | #include "llvm/ADT/Optional.h"
25 |
26 | #include "AST.hpp"
27 | #include "ASTTraversal.hpp"
28 |
29 | /// Converts the ASTNode to it's most important representing value
30 | class ASTStringer {
31 | template >::value>>
33 | static llvm::Optional toStringImpl(T const* /*node*/) {
34 | return llvm::None;
35 | }
36 |
37 | // General implementation for decl contexts
38 | static llvm::Optional toStringImpl(NamedDeclContext const* decl);
39 |
40 | static llvm::Optional
41 | toStringImpl(DeclRefExprASTNode const* node);
42 | static llvm::Optional
43 | toStringImpl(IntegerLiteralExprASTNode const* node);
44 | static llvm::Optional
45 | toStringImpl(BooleanLiteralExprASTNode const* node);
46 | static llvm::Optional
47 | toStringImpl(BinaryOperatorExprASTNode const* node);
48 |
49 | public:
50 | /// Returns the type name of the given ASTNode.
51 | static llvm::StringRef toTypeString(ASTNode const* node);
52 |
53 | /// Returns the most relevant information about the given ASTNode
54 | /// if there is any.
55 | static llvm::Optional toString(ASTNode const* node) {
56 | return traverseNode(
57 | node, [=](auto const* promoted) { return toStringImpl(promoted); });
58 | }
59 | };
60 |
61 | #endif // #ifndef AST_STRINGER_HPP_INCLUDED__
62 |
--------------------------------------------------------------------------------
/src/AST/ASTVisitor.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef AST_VISITOR_HPP_INCLUDED__
19 | #define AST_VISITOR_HPP_INCLUDED__
20 |
21 | #include "ASTPredicate.hpp"
22 | #include "ASTTraversal.hpp"
23 |
24 | class ASTNode;
25 | // Forward declare all ASTNodes
26 | #define FOR_EACH_AST_NODE(NAME) class NAME##ASTNode;
27 | #include "AST.inl"
28 |
29 | /// Returns a default value for the given type
30 | template struct DefaultValueFactory {
31 | Type operator()() const { return Type{}; }
32 | };
33 | template <> struct DefaultValueFactory {};
34 |
35 | /// A default merge implementation for the given type
36 | template struct DefaultCombiner;
37 | template <> struct DefaultCombiner {};
38 |
39 | /// An adaptable base class for visiting ASTNodes
40 | template ,
42 | typename DefaultValueFactoryType = DefaultValueFactory>
43 | class ASTVisitor {
44 | CombinerType combiner_;
45 | DefaultValueFactoryType defaultFactory_;
46 |
47 | public:
48 | ASTVisitor() = default;
49 | virtual ~ASTVisitor() = default;
50 |
51 | #define FOR_EACH_AST_NODE(NAME) \
52 | virtual ResultType visit(NAME##ASTNode const* node) { \
53 | return visitChildren(node); \
54 | }
55 | #include "AST.inl"
56 |
57 | ResultType visitChildren(ASTNode const* node) {
58 | /// Manual promote
59 | return traverseNode(node, [=](auto* promoted) {
60 | return visitChildrenImpl(std::common_type{}, promoted);
61 | });
62 | }
63 |
64 | virtual ResultType accept(ASTNode const* node) {
65 | return traverseNode(node, [=](auto* promoted) { return visit(promoted); });
66 | }
67 |
68 | private:
69 | void visitChildrenImpl(std::common_type, ASTNode const* node) {
70 | traverseNodeIf(node, pred::hasChildren(), [&](auto promoted) {
71 | for (auto child : promoted->children()) {
72 | accept(child);
73 | }
74 | });
75 | }
76 | template
77 | ResultType visitChildrenImpl(std::common_type, ASTNode const* node) {
78 | auto combined = defaultFactory_();
79 | traverseNodeIf(node, pred::hasChildren(), [&](auto promoted) {
80 | for (auto child : promoted->children()) {
81 | combined = combiner_(combined, accept(child));
82 | }
83 | });
84 | return combined;
85 | }
86 | };
87 |
88 | #endif // #ifndef AST_VISITOR_HPP_INCLUDED__
89 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Parser & Lexer
2 | list(APPEND GENERATED_SOURCES
3 | "${CMAKE_BINARY_DIR}/Generated/GeneratedLexer.h"
4 | "${CMAKE_BINARY_DIR}/Generated/GeneratedLexer.cpp"
5 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParser.h"
6 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParser.cpp"
7 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserBaseListener.cpp"
8 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserBaseListener.h"
9 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserBaseVisitor.cpp"
10 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserBaseVisitor.h"
11 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserListener.cpp"
12 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserListener.h"
13 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserVisitor.cpp"
14 | "${CMAKE_BINARY_DIR}/Generated/GeneratedParserVisitor.h")
15 |
16 | add_custom_command(
17 | OUTPUT
18 | ${GENERATED_SOURCES}
19 | COMMAND
20 | ${Java_JAVA_EXECUTABLE}
21 | -jar ${CMAKE_BINARY_DIR}/antlr4-complete.jar
22 | -Dlanguage=Cpp -listener -visitor -o ${CMAKE_BINARY_DIR}/Generated
23 | ${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedLexer.g4
24 | ${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedParser.g4
25 | DEPENDS
26 | "${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedLexer.g4"
27 | "${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedParser.g4"
28 | VERBATIM)
29 |
30 | add_custom_target(GenerateLexerParser
31 | SOURCES
32 | "${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedLexer.g4"
33 | "${CMAKE_CURRENT_LIST_DIR}/Parse/GeneratedParser.g4"
34 | DEPENDS
35 | ${GENERATED_SOURCES})
36 |
37 | source_group("Parse\\Generated"
38 | FILES
39 | ${GENERATED_SOURCES})
40 |
41 | # Compiler
42 | CollectSourceFiles(
43 | ${CMAKE_CURRENT_LIST_DIR}
44 | PRIVATE_SOURCES
45 | # Exclude
46 | ${CMAKE_CURRENT_LIST_DIR}/PCH)
47 |
48 | CollectIncludeDirectories(
49 | ${CMAKE_CURRENT_LIST_DIR}
50 | PUBLIC_INCLUDES
51 | # Exclude
52 | ${CMAKE_CURRENT_LIST_DIR}/PCH)
53 |
54 | if (USE_PCH)
55 | set(PRIVATE_PCH_HEADER ${CMAKE_CURRENT_LIST_DIR}/PCH/PCH.hpp)
56 | endif()
57 |
58 | add_executable(compiler
59 | ${PRIVATE_SOURCES}
60 | ${GENERATED_SOURCES}
61 | ${CMAKE_SOURCE_DIR}/lang/main.swy)
62 |
63 | add_dependencies(compiler GenerateLexerParser)
64 |
65 | target_link_libraries(compiler
66 | PUBLIC
67 | fmt
68 | llvm
69 | PRIVATE
70 | antlr4
71 | function2)
72 |
73 | target_include_directories(compiler
74 | PRIVATE
75 | "${CMAKE_CURRENT_LIST_DIR}"
76 | "${CMAKE_CURRENT_LIST_DIR}/AST"
77 | "${CMAKE_CURRENT_LIST_DIR}/Codegen"
78 | "${CMAKE_CURRENT_LIST_DIR}/Diag"
79 | "${CMAKE_CURRENT_LIST_DIR}/Frontend"
80 | "${CMAKE_CURRENT_LIST_DIR}/Parse"
81 | "${CMAKE_CURRENT_LIST_DIR}/Sema"
82 | "${CMAKE_CURRENT_LIST_DIR}/Support"
83 | "${CMAKE_CURRENT_LIST_DIR}/Tooling"
84 | "${CMAKE_BINARY_DIR}/Generated")
85 |
86 | target_compile_features(compiler
87 | PRIVATE
88 | ${CXX14_FEATURES}
89 | PUBLIC
90 | ${CXX11_FEATURES})
91 |
92 | if(USE_PCH)
93 | set_target_properties(compiler
94 | PROPERTIES
95 | # Set the PCH header
96 | COTIRE_CXX_PREFIX_HEADER_INIT "${PRIVATE_PCH_HEADER}"
97 | # Disable unity builds
98 | COTIRE_ADD_UNITY_BUILD FALSE)
99 |
100 | cotire(compiler)
101 | endif()
102 |
103 | target_compile_definitions(compiler
104 | PRIVATE
105 | "-DSOURCE_DIRECTORY=\"${CMAKE_SOURCE_DIR}\"")
106 |
107 | group_sources(${CMAKE_CURRENT_LIST_DIR})
108 | # source_group("\\Parse\\Generated" FILES ${GENERATED_SOURCES})
109 |
--------------------------------------------------------------------------------
/src/Codegen/CodegenBase.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef CODEGEN_BASE_HPP_INCLUDED__
19 | #define CODEGEN_BASE_HPP_INCLUDED__
20 |
21 | #include
22 |
23 | #include "llvm/ADT/StringRef.h"
24 |
25 | namespace llvm {
26 | class LLVMContext;
27 | class Type;
28 | class FunctionType;
29 | class Function;
30 | class Module;
31 | class Constant;
32 | }
33 |
34 | class CompilationUnit;
35 | class UnitASTNode;
36 | class FunctionDeclASTNode;
37 | class MetaDeclASTNode;
38 | class IntegerLiteralExprASTNode;
39 | class BooleanLiteralExprASTNode;
40 | class DeclStmtASTNode;
41 | class AnonymousArgumentDeclASTNode;
42 | class MetaInstantiationExprASTNode;
43 |
44 | /// Provides basic support methods for codegen classes,
45 | /// which usually are a bridge between ASTNodes and it's llvm::Type's.
46 | template class CodegenBase {
47 | public:
48 | CodegenBase() = default;
49 |
50 | /// Returns the type of an integer literal
51 | llvm::Type* getTypeOf(IntegerLiteralExprASTNode const* node);
52 | /// Returns the type of a boolean literal
53 | llvm::Type* getTypeOf(BooleanLiteralExprASTNode const* node);
54 | /// Returns the type of a DeclStmtASTNode
55 | llvm::Type* getTypeOf(DeclStmtASTNode const* node);
56 | /// Returns the llvm type of the given AnonymousArgumentDeclASTNode
57 | llvm::Type* getTypeOf(AnonymousArgumentDeclASTNode const* node);
58 |
59 | /// Returns the type of int
60 | llvm::Type* getTypeOfInt();
61 | /// Returns the type of void
62 | llvm::Type* getTypeOfVoid();
63 |
64 | /// Returns the function type of the given FunctionDeclASTNode
65 | llvm::FunctionType* getFunctionTypeOf(FunctionDeclASTNode const* node);
66 | /// Returns the meta function type of the given MetaDeclASTNode
67 | /// which is used to generate the yield of a meta instantiation.
68 | llvm::FunctionType* getFunctionTypeOf(MetaDeclASTNode const* node);
69 |
70 | /// Returns the mangled name of the given global node
71 | static std::string mangleSymbolOf(llvm::StringRef name);
72 | /// Returns the mangled name of the given global node
73 | static std::string mangleNameOf(FunctionDeclASTNode const* node);
74 | /// Returns the mangled name of the given global node
75 | static std::string mangleNameOf(MetaDeclASTNode const* node);
76 | /// Returns the mangled name of the given global node
77 | static std::string mangleNameOf(MetaInstantiationExprASTNode const* node);
78 |
79 | /// Returns a forward declaration to the given function
80 | llvm::Constant* createFunctionPrototype(llvm::Function* function);
81 | /// Returns a forward declaration to the given function
82 | llvm::Constant* createFunctionPrototype(FunctionDeclASTNode const* node);
83 | /// Returns a forward declaration to the given function
84 | llvm::Constant* createFunctionPrototype(MetaDeclASTNode const* node);
85 |
86 | /// Creates a function with the given name and type into the current module
87 | llvm::Function* createFunction(llvm::StringRef name,
88 | llvm::FunctionType* type);
89 |
90 | /// Creates a function with the given name and type into the given module
91 | static llvm::Function* createFunction(llvm::Module* module,
92 | llvm::StringRef name,
93 | llvm::FunctionType* type);
94 |
95 | /// Returns the type of the (first) context argument in meta functions
96 | /// which usually references to the ASTLayoutWriter object.
97 | llvm::Type* getTypeOfContextPtr();
98 | /// Returns a prototype of the contribution callback
99 | llvm::Constant* createContributeCallbackPrototype();
100 | /// Returns a prototype of the reduce callback
101 | llvm::Constant* createReduceCallbackPrototype();
102 | /// Returns a prototype of the introduce callback
103 | llvm::Constant* createIntroduceCallbackPrototype();
104 |
105 | /// Returns a constant to the given pointer
106 | llvm::Constant* getPointerConstant(void const* ptr);
107 |
108 | /// Returns true when no error was submitted to the
109 | /// associated DiagnosticEngine
110 | bool canContinue();
111 |
112 | private:
113 | llvm::LLVMContext& context();
114 | llvm::Module* module();
115 | CompilationUnit* compilationUnit();
116 | };
117 |
118 | #endif // #ifndef CODEGEN_BASE_HPP_INCLUDED__
119 |
--------------------------------------------------------------------------------
/src/Codegen/CodegenInstance.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef CODEGEN_INSTANCE_HPP_INCLUDED__
19 | #define CODEGEN_INSTANCE_HPP_INCLUDED__
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #include "llvm/ADT/Optional.h"
26 | #include "llvm/ADT/PointerUnion.h"
27 |
28 | #include "CodeExecutor.hpp"
29 | #include "CodegenBase.hpp"
30 | #include "IRContext.hpp"
31 | #include "Nullable.hpp"
32 | #include "ScopeLeaveAction.hpp"
33 |
34 | namespace llvm {
35 | class Module;
36 | class LLVMContext;
37 | class Function;
38 | class FunctionType;
39 | class Type;
40 | class Constant;
41 | namespace legacy {
42 | class FunctionPassManager;
43 | }
44 | }
45 |
46 | class ASTContext;
47 | class ASTNode;
48 | class CompilationUnit;
49 | class FunctionDeclASTNode;
50 | class AnonymousArgumentDeclASTNode;
51 | class CompilationUnitASTNode;
52 | class MetaASTEvaluator;
53 | class CodegenInstance;
54 |
55 | /// Provides the facility for generating LLVM IR from the AST
56 | class CodegenInstance : public IRContext, public CodegenBase {
57 | CompilationUnit* compilationUnit_;
58 | ASTContext* astContext_;
59 | std::unique_ptr codeExecuter_;
60 |
61 | std::unique_ptr llvmContext_;
62 | std::unique_ptr amalgamation_;
63 |
64 | std::unique_ptr passManager_;
65 |
66 | /// Contains the dependencies which still must be generated
67 | std::unordered_set dependencies_;
68 |
69 | /// Contains the current generated functions, useful for cycle detection
70 | std::unordered_set currentGeneration_;
71 |
72 | std::unordered_map>
75 | functionSource_;
76 |
77 | CodegenInstance(CompilationUnit* compilationUnit, ASTContext* astContext);
78 |
79 | public:
80 | ~CodegenInstance();
81 |
82 | static std::unique_ptr
83 | createFor(CompilationUnit* compilationUnit, ASTContext* astContext);
84 |
85 | CompilationUnit* getCompilationUnit() override;
86 | ASTContext* getASTContext() override { return astContext_; }
87 | llvm::LLVMContext& getLLVMContext() override;
88 | llvm::Module* getModule() override;
89 | llvm::Constant* lookupGlobal(FunctionDeclASTNode const* function) override;
90 | Nullable
91 | lookupGlobal(MetaInstantiationExprASTNode const* inst,
92 | bool requiresCompleted = false) override;
93 | Nullable
94 | resolveGlobal(llvm::Function const* function) override;
95 | Nullable
96 | resolveGlobal(FunctionDeclASTNode const* function) override;
97 | Nullable
98 | resolveGlobal(MetaInstantiationExprASTNode const* inst) override;
99 |
100 | /// Generates the IR for the given CompilationUnitASTNode
101 | bool codegen(CompilationUnitASTNode const* compilationUnitASTNode);
102 |
103 | /// Dumps the module to stdout
104 | void dump();
105 |
106 | private:
107 | /// Mark an ASTNode as currently generated to detect strong cycles
108 | ScopeLeaveAction enterGeneration(ASTNode const* node);
109 |
110 | /// Codegens the body of a function
111 | Nullable codegen(FunctionDeclASTNode const* node);
112 |
113 | Nullable codegen(MetaInstantiationExprASTNode const* node);
114 |
115 | /// Codegen dummy
116 | bool codegen(ASTNode const* /*node*/) { return true; }
117 |
118 | /// Instantiates the given MetaInstantiation and returns
119 | /// it's exported node on success.
120 | Nullable instantiate(MetaInstantiationExprASTNode const* inst,
121 | bool requiresCompleted = false);
122 |
123 | /// Runs optimization passes on the function depending
124 | /// on the configured optimization level.
125 | void optimizeFunction(llvm::Function* function);
126 | };
127 |
128 | #endif // #ifndef CODEGEN_INSTANCE_HPP_INCLUDED__
129 |
--------------------------------------------------------------------------------
/src/Codegen/FunctionCodegen.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef FUNCTION_CODEGEN_HPP_INCLUDED__
19 | #define FUNCTION_CODEGEN_HPP_INCLUDED__
20 |
21 | #include "llvm/ADT/ArrayRef.h"
22 | #include "llvm/ADT/Optional.h"
23 | #include "llvm/ADT/STLExtras.h"
24 | #include "llvm/ADT/ScopedHashTable.h"
25 | #include "llvm/ExecutionEngine/GenericValue.h"
26 | #include "llvm/IR/IRBuilder.h"
27 | #include "llvm/IR/Module.h"
28 |
29 | #include "CodegenBase.hpp"
30 | #include "IRContext.hpp"
31 | #include "Nullable.hpp"
32 |
33 | namespace llvm {
34 | class Module;
35 | class LLVMContext;
36 | class Function;
37 | class FunctionType;
38 | class Type;
39 | class BasicBlock;
40 | class Value;
41 | }
42 |
43 | class ASTContext;
44 | class ASTNode;
45 | class CompilationUnit;
46 | class CompilationUnitASTNode;
47 | class FunctionDeclASTNode;
48 | class AnonymousArgumentDeclASTNode;
49 | class NamedDeclContext;
50 | class MetaInstantiationExprASTNode;
51 | class DeclRefExprASTNode;
52 | class ArgumentDeclListASTNode;
53 | class StmtASTNode;
54 | #define FOR_EACH_STMT_NODE(NAME) class NAME##ASTNode;
55 | #include "AST.inl"
56 | class ExprASTNode;
57 | #define FOR_EACH_EXPR_NODE(NAME) class NAME##ASTNode;
58 | #include "AST.inl"
59 | class MetaCodegen;
60 |
61 | /// Responsible for codegening a single function
62 | /// Preserves a state for values that are known within the function
63 | class FunctionCodegen : public IRContextReplication,
64 | public CodegenBase {
65 | friend class MetaCodegen;
66 |
67 | public:
68 | using ValueMap = llvm::ScopedHashTable;
69 |
70 | private:
71 | llvm::Function* function_;
72 |
73 | llvm::IRBuilder<> builder_;
74 | ValueMap values_;
75 |
76 | public:
77 | FunctionCodegen(IRContext* context, llvm::Function* function);
78 |
79 | /// Codegens the function body
80 | void codegen(FunctionDeclASTNode const* node);
81 |
82 | llvm::BasicBlock* createEntryBlock();
83 |
84 | llvm::BasicBlock* setUpStackFrame(ArgumentDeclListASTNode const* args,
85 | bool isReadOnly = false,
86 | bool isThisCall = false);
87 |
88 | /// Introduces the value as known in the current scope
89 | void introduce(NamedDeclContext const* decl, llvm::Value* value) {
90 | values_.insert(decl, value);
91 | }
92 | /// Looks up the given NamedDeclContext and finds its associated Value
93 | /// in the local context. The value is never expected to be null!
94 | llvm::Value* lookupLocal(NamedDeclContext const* decl);
95 |
96 | /// Returns the llvm::Function for which the
97 | /// FunctionCodegen is responsible for
98 | llvm::Function* getFunction() const { return function_; }
99 |
100 | /// Creates a llvm::BasicBlock
101 | llvm::BasicBlock* createBlock(llvm::StringRef name);
102 | /// Creates a llvm::BasicBlock before the given block
103 | llvm::BasicBlock* createBlockBefore(llvm::BasicBlock* block,
104 | llvm::StringRef name);
105 | /// Creates a llvm::BasicBlock after the given block and jumps to it
106 | llvm::BasicBlock* createRegionAfter(llvm::BasicBlock* block,
107 | llvm::StringRef name);
108 |
109 | /// Codegens a statement, returns the current basic block when
110 | /// the scope can be continued (it wasn't terminated).
111 | Nullable codegenStmt(llvm::BasicBlock* block,
112 | StmtASTNode const* stmt);
113 | #define FOR_EACH_STMT_NODE(NAME) \
114 | Nullable codegenStmt(llvm::BasicBlock* block, \
115 | NAME##ASTNode const* stmt);
116 | #include "AST.inl"
117 |
118 | llvm::Value* codegenExpr(ExprASTNode const* expr);
119 | #define FOR_EACH_EXPR_NODE(NAME) \
120 | llvm::Value* codegenExpr(NAME##ASTNode const* expr);
121 | #include "AST.inl"
122 |
123 | /// Represents a codegen supplier ref which can be used for providing
124 | /// a function that generates unknown statements into the given block.
125 | using CodegenSupplier =
126 | llvm::function_ref(llvm::BasicBlock*)>;
127 |
128 | /// Creates the skeleton for an if structure and invokes the CodegenSupplier
129 | /// at the appropriate position of statement insertion.
130 | Nullable
131 | codegenIfStructure(llvm::BasicBlock* block, ExprASTNode const* condition,
132 | CodegenSupplier codegenTrue,
133 | llvm::Optional codegenFalse = llvm::None);
134 |
135 | /// Loads pointer values from memory
136 | llvm::Value* loadMemory(llvm::Value* value);
137 | };
138 |
139 | #endif // #ifndef FUNCTION_CODEGEN_HPP_INCLUDED__
140 |
--------------------------------------------------------------------------------
/src/Codegen/IRContext.cpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #include "IRContext.hpp"
19 |
--------------------------------------------------------------------------------
/src/Codegen/IRContext.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef IRCONTEXT_INCLUDED__
19 | #define IRCONTEXT_INCLUDED__
20 |
21 | #include "Nullable.hpp"
22 |
23 | namespace llvm {
24 | class Module;
25 | class LLVMContext;
26 | class Constant;
27 | class FunctionType;
28 | class Function;
29 | }
30 |
31 | class ASTContext;
32 | class CompilationUnit;
33 | class FunctionDeclASTNode;
34 | class MetaInstantiationExprASTNode;
35 |
36 | /// Represents a class independent context retrieval layer
37 | /// which provides information about the current context and module.
38 | class IRContext {
39 | public:
40 | IRContext() = default;
41 | virtual ~IRContext() = default;
42 |
43 | /// Returns the module of the context
44 | virtual CompilationUnit* getCompilationUnit() = 0;
45 | /// Returns the ASTContext
46 | virtual ASTContext* getASTContext() = 0;
47 | /// Returns the LLVM of the context
48 | virtual llvm::LLVMContext& getLLVMContext() = 0;
49 | /// Returns the module of the context
50 | virtual llvm::Module* getModule() = 0;
51 |
52 | /// Looks the given function decl up inside the current context which
53 | /// potentially can return an ungenerated prototype of the global.
54 | virtual llvm::Constant* lookupGlobal(FunctionDeclASTNode const* function) = 0;
55 | /// Looks the given instantiation up inside the current context which
56 | /// potentially can return an ungenerated prototype of the global.
57 | virtual Nullable
58 | lookupGlobal(MetaInstantiationExprASTNode const* inst,
59 | bool requiresCompleted = false) = 0;
60 |
61 | /// Resolves the given function inside the current context which
62 | /// returns a guaranteed completed global.
63 | virtual Nullable
64 | resolveGlobal(llvm::Function const* function) = 0;
65 | /// Resolves the given function decl inside the current context which
66 | /// returns a guaranteed completed global.
67 | virtual Nullable
68 | resolveGlobal(FunctionDeclASTNode const* function) = 0;
69 | /// Resolves the given instantiation inside the current context which
70 | /// returns a guaranteed completed global.
71 | virtual Nullable
72 | resolveGlobal(MetaInstantiationExprASTNode const* inst) = 0;
73 | };
74 |
75 | /// Replicates the underlaying IRContext and makes it's methods to members
76 | class IRContextReplication {
77 | IRContext* context_;
78 |
79 | public:
80 | explicit IRContextReplication(IRContext* context) : context_(context) {}
81 |
82 | IRContext* getIRContext() { return context_; }
83 | CompilationUnit* getCompilationUnit() {
84 | return context_->getCompilationUnit();
85 | }
86 | ASTContext* getASTContext() { return context_->getASTContext(); }
87 | llvm::LLVMContext& getLLVMContext() { return context_->getLLVMContext(); }
88 | llvm::Module* getModule() { return context_->getModule(); }
89 | llvm::Constant* lookupGlobal(FunctionDeclASTNode const* function) {
90 | return context_->lookupGlobal(function);
91 | }
92 | Nullable
93 | lookupGlobal(MetaInstantiationExprASTNode const* inst,
94 | bool requiresCompleted = false) {
95 | return context_->lookupGlobal(inst, requiresCompleted);
96 | }
97 | Nullable resolveGlobal(llvm::Function const* function) {
98 | return context_->resolveGlobal(function);
99 | }
100 | Nullable resolveGlobal(FunctionDeclASTNode const* function) {
101 | return context_->resolveGlobal(function);
102 | }
103 | Nullable
104 | resolveGlobal(MetaInstantiationExprASTNode const* inst) {
105 | return context_->resolveGlobal(inst);
106 | }
107 | };
108 |
109 | #endif // #ifndef IRCONTEXT_INCLUDED__
110 |
--------------------------------------------------------------------------------
/src/Codegen/MetaCodegen.hpp:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright(c) 2016 - 2017 Denis Blank
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | **/
17 |
18 | #ifndef META_CODEGEN_CODEGEN_HPP_INCLUDED__
19 | #define META_CODEGEN_CODEGEN_HPP_INCLUDED__
20 |
21 | #include "ASTCursor.hpp"
22 | #include "FunctionCodegen.hpp"
23 | #include "IRContext.hpp"
24 | #include "Nullable.hpp"
25 |
26 | namespace llvm {
27 | class Function;
28 | class BasicBlock;
29 | class Instruction;
30 | class Value;
31 | }
32 |
33 | class ASTNode;
34 | class IRContext;
35 | class MetaDeclASTNode;
36 | class MetaASTEvaluator;
37 | class MetaContributionASTNode;
38 | class MetaInstantiationExprASTNode;
39 | class MetaIfStmtASTNode;
40 | class MetaCalculationStmtASTNode;
41 |
42 | /// Is responsible for codegening a single meta decl
43 | /// Preserves a state for values that are known within the function
44 | class MetaCodegen : public IRContextReplication,
45 | public CodegenBase