├── .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 | Compiler 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 | Pipeline 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