├── .gitignore ├── .gitmodules ├── .travis.yml ├── .travis ├── install.sh └── run_tests.sh ├── CMakeLists.txt ├── README.MD ├── cmake ├── CreateGperfHeader.cmake ├── FindGperf.cmake ├── FindGraphViz.cmake ├── FindJSON-C.cmake ├── RFRefuConfig.cmake ├── RFTargetSources.cmake └── RFUseLLVM.cmake ├── docs ├── Makefile ├── conf.py ├── getting_started.rst ├── index.rst ├── make.bat └── reference.rst ├── include ├── analyzer │ ├── analyzer.h │ ├── analyzer_pass1.h │ ├── symbol_table.h │ ├── type_set.h │ ├── typecheck.h │ ├── typecheck_arr.h │ ├── typecheck_forexpr.h │ ├── typecheck_functions.h │ └── typecheck_matchexpr.h ├── ast │ ├── arr.h │ ├── arr_decls.h │ ├── ast.h │ ├── ast_utils.h │ ├── block.h │ ├── block_decls.h │ ├── constants.h │ ├── constants_decls.h │ ├── forexpr.h │ ├── forexpr_decls.h │ ├── function.h │ ├── function_decls.h │ ├── generics.h │ ├── generics_decls.h │ ├── identifier.h │ ├── ifexpr.h │ ├── ifexpr_decls.h │ ├── iterable.h │ ├── iterable_decls.h │ ├── matchexpr.h │ ├── matchexpr_decls.h │ ├── module.h │ ├── module_decls.h │ ├── operators.h │ ├── operators_decls.h │ ├── returnstmt.h │ ├── returnstmt_decls.h │ ├── string_literal.h │ ├── string_literal_decls.h │ ├── type.h │ ├── type_decls.h │ ├── typeclass.h │ ├── typeclass_decls.h │ ├── vardecl.h │ └── vardecl_decls.h ├── backend │ └── llvm.h ├── compiler.h ├── compiler_args.h ├── front_ctx.h ├── info │ ├── info.h │ └── msg.h ├── inpfile.h ├── inplocation.h ├── inpoffset.h ├── inpstr.h ├── ir │ ├── parser │ │ ├── rirparser.h │ │ └── rirtoken.h │ ├── rir.h │ ├── rir_argument.h │ ├── rir_array.h │ ├── rir_binaryop.h │ ├── rir_block.h │ ├── rir_branch.h │ ├── rir_call.h │ ├── rir_common.h │ ├── rir_constant.h │ ├── rir_convert.h │ ├── rir_expression.h │ ├── rir_function.h │ ├── rir_global.h │ ├── rir_object.h │ ├── rir_process.h │ ├── rir_strmap.h │ ├── rir_type.h │ ├── rir_typedef.h │ ├── rir_unaryop.h │ ├── rir_utils.h │ ├── rir_value.h │ └── rir_variable.h ├── lexer │ ├── lexer.h │ └── tokens.h ├── module.h ├── ownership │ └── ownership.h ├── parser │ ├── parser.h │ └── parser_common.h ├── serializer │ └── serializer.h ├── types │ ├── type.h │ ├── type_arr.h │ ├── type_comparisons.h │ ├── type_decls.h │ ├── type_elementary.h │ ├── type_function.h │ ├── type_operators.h │ └── type_utils.h └── utils │ ├── common.h │ ├── common_strings.h │ ├── data.h │ ├── string_set.h │ └── traversal.h ├── lib ├── CMakeLists.txt └── argtable │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README │ ├── argtable3.c │ ├── argtable3.h │ ├── examples │ ├── Makefile │ ├── Makefile.nmake │ ├── echo.c │ ├── ls.c │ ├── multisyntax.c │ ├── mv.c │ ├── myprog.c │ ├── myprog_C89.c │ ├── testargtable3.c │ └── uname.c │ └── tests │ ├── CuTest.c │ ├── CuTest.h │ ├── Makefile │ ├── Makefile.nmake │ ├── testall.c │ ├── testargdate.c │ ├── testargdbl.c │ ├── testargfile.c │ ├── testargint.c │ ├── testarglit.c │ ├── testargrex.c │ └── testargstr.c ├── src ├── CMakeLists.txt ├── analyzer │ ├── CMakeLists.txt │ ├── analyzer.c │ ├── analyzer_pass1.c │ ├── symbol_table.c │ ├── type_set.c │ ├── typecheck.c │ ├── typecheck_arr.c │ ├── typecheck_forexpr.c │ ├── typecheck_functions.c │ └── typecheck_matchexpr.c ├── ast │ ├── CMakeLists.txt │ ├── arr.c │ ├── ast.c │ ├── ast_type_traversal.c │ ├── ast_utils.c │ ├── block.c │ ├── constants.c │ ├── forexpr.c │ ├── function.c │ ├── generics.c │ ├── identifier.c │ ├── ifexpr.c │ ├── iterable.c │ ├── matchexpr.c │ ├── module.c │ ├── operators.c │ ├── returnstmt.c │ ├── string_literal.c │ ├── type.c │ ├── typeclass.c │ └── vardecl.c ├── backend │ ├── CMakeLists.txt │ ├── llvm.c │ ├── llvm_arrays.c │ ├── llvm_arrays.h │ ├── llvm_ast.c │ ├── llvm_ast.h │ ├── llvm_conversion.c │ ├── llvm_conversion.h │ ├── llvm_functions.c │ ├── llvm_functions.h │ ├── llvm_globals.c │ ├── llvm_globals.h │ ├── llvm_operators.c │ ├── llvm_operators.h │ ├── llvm_types.c │ ├── llvm_types.h │ ├── llvm_utils.c │ ├── llvm_utils.h │ ├── llvm_values.c │ └── llvm_values.h ├── compiler.c ├── compiler_args.c ├── front_ctx.c ├── info │ ├── CMakeLists.txt │ ├── info.c │ └── msg.c ├── inpfile.c ├── inplocation.c ├── inpoffset.c ├── inpstr.c ├── ir │ ├── CMakeLists.txt │ ├── parser │ │ ├── CMakeLists.txt │ │ ├── rirparser.c │ │ ├── rirtoken.c │ │ ├── rirtoken_htable.gperf │ │ ├── rparse_binaryop.c │ │ ├── rparse_blocks.c │ │ ├── rparse_expressions.c │ │ ├── rparse_functions.c │ │ ├── rparse_global.c │ │ ├── rparse_typedef.c │ │ ├── rparse_utils.c │ │ └── rparse_value.c │ ├── rir.c │ ├── rir_argument.c │ ├── rir_array.c │ ├── rir_binaryop.c │ ├── rir_block.c │ ├── rir_branch.c │ ├── rir_call.c │ ├── rir_common.c │ ├── rir_constant.c │ ├── rir_convert.c │ ├── rir_expression.c │ ├── rir_function.c │ ├── rir_global.c │ ├── rir_loops.c │ ├── rir_object.c │ ├── rir_process.c │ ├── rir_process_cond.c │ ├── rir_process_match.c │ ├── rir_strmap.c │ ├── rir_type.c │ ├── rir_typedef.c │ ├── rir_unaryop.c │ ├── rir_utils.c │ ├── rir_value.c │ └── rir_variable.c ├── lexer │ ├── CMakeLists.txt │ ├── common.h │ ├── lexer.c │ ├── tokens.c │ └── tokens_htable.gperf ├── main.c ├── module.c ├── ownership │ ├── CMakeLists.txt │ ├── ow_debug.h │ ├── ow_edge.c │ ├── ow_edge.h │ ├── ow_graph.c │ ├── ow_graph.h │ ├── ow_graphviz.c │ ├── ow_graphviz.h │ ├── ow_node.c │ ├── ow_node.h │ └── ownership.c ├── parser │ ├── CMakeLists.txt │ ├── parser.c │ ├── parser_common.c │ └── recursive_descent │ │ ├── CMakeLists.txt │ │ ├── arr.c │ │ ├── arr.h │ │ ├── block.c │ │ ├── block.h │ │ ├── common.h │ │ ├── core.c │ │ ├── expression.c │ │ ├── expression.h │ │ ├── forexpr.c │ │ ├── forexpr.h │ │ ├── function.c │ │ ├── function.h │ │ ├── generics.c │ │ ├── generics.h │ │ ├── identifier.c │ │ ├── identifier.h │ │ ├── ifexpr.c │ │ ├── ifexpr.h │ │ ├── matchexpr.c │ │ ├── matchexpr.h │ │ ├── module.c │ │ ├── module.h │ │ ├── type.c │ │ ├── type.h │ │ ├── typeclass.c │ │ ├── typeclass.h │ │ ├── vardecl.c │ │ └── vardecl.h ├── serializer │ ├── CMakeLists.txt │ ├── astprinter.c │ ├── astprinter.h │ └── serializer.c ├── types │ ├── CMakeLists.txt │ ├── elementary_types_htable.gperf │ ├── type.c │ ├── type_arr.c │ ├── type_comparisons.c │ ├── type_creation.c │ ├── type_elementary.c │ ├── type_function.c │ ├── type_operators.c │ └── type_utils.c └── utils │ ├── CMakeLists.txt │ ├── common_strings.c │ ├── data.c │ ├── string_set.c │ └── traversal.c ├── stdlib └── io.rf ├── test.sh └── test ├── CMakeLists.txt ├── Dockerfile ├── analyzer ├── CMakeLists.txt ├── test_modules.c ├── test_symbol_table.c ├── test_typecheck.c ├── test_typecheck_arr.c ├── test_typecheck_conversion.c ├── test_typecheck_forexpr.c ├── test_typecheck_functions.c ├── test_typecheck_matchexpr.c ├── test_typecheck_operators.c ├── testsupport_analyzer.c └── testsupport_analyzer.h ├── end_to_end ├── CMakeLists.txt ├── test_end_to_end_basic.c ├── test_end_to_end_modules.c ├── testsupport_end_to_end.c └── testsupport_end_to_end.h ├── lexer ├── CMakeLists.txt ├── test_lexer.c ├── testsupport_lexer.c └── testsupport_lexer.h ├── parser ├── CMakeLists.txt ├── test_parser_block.c ├── test_parser_forexpr.c ├── test_parser_function.c ├── test_parser_generics.c ├── test_parser_ifexpr.c ├── test_parser_matchexpr.c ├── test_parser_misc.c ├── test_parser_modules.c ├── test_parser_operators.c ├── test_parser_typeclass.c ├── test_parser_typedesc.c ├── testsupport_parser.c └── testsupport_parser.h ├── rir ├── CMakeLists.txt ├── creation │ ├── CMakeLists.txt │ └── test_create_simple.c ├── test_finalized_ast.c ├── test_ownership.c ├── test_parsing_rir.c ├── test_rir_end_to_end.c ├── test_rir_misc.c ├── testsupport_rir.c ├── testsupport_rir.h ├── testsupport_rir_compare.c └── testsupport_rir_compare.h ├── test_input_base.c ├── test_main.c ├── testsupport.c ├── testsupport.h ├── testsupport_front.c ├── testsupport_front.h └── types ├── CMakeLists.txt ├── test_types.c └── test_typeset.c /.gitignore: -------------------------------------------------------------------------------- 1 | # scons related 2 | .sconsign.dblite 3 | .sconf_temp 4 | build_test 5 | # unit test executable 6 | check_exec 7 | # cmake related 8 | build/ 9 | 10 | 11 | # object files 12 | *.pyc 13 | *.o 14 | # malinka created files 15 | compile_commands.json 16 | 17 | # the executable 18 | refu 19 | 20 | # refulib logs 21 | *.log 22 | 23 | # generated files 24 | src/lexer/tokens_htable.h 25 | src/ir/parser/rirtoken_htable.h 26 | src/types/builtin_types_htable.h 27 | src/types/elementary_types_htable.h 28 | 29 | # test generated files 30 | test_input_file.rf 31 | test_input_file.rf.exe 32 | test_input_file.rir.exe 33 | 34 | # documentation related files 35 | docs/_build/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rfbase"] 2 | path = rfbase 3 | url = https://github.com/refu-lang/rfbase.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Refulang travis yaml file 2 | # 3 | # We run the tests inside a docker instance since that way it's easier to setup a development 4 | # environment containing LLVM and the other dependencies that refulang has 5 | # 6 | # -- Some useful links of other travis file 7 | # This seems to be a nice travis file for using many different llvm versions. 8 | # https://github.com/scross99/locic/blob/master/.travis.yml 9 | # This is using docker and many llvm versions: 10 | # https://github.com/fuzzylite/fuzzylite/blob/master/.travis.yml 11 | # And rust changed to using docker due to the LLVM Apt server being brought offline 12 | # https://github.com/rust-lang/rust/commit/b1651fb4d2c0349ccca108b8d24210d688507936 13 | 14 | language: c 15 | sudo: required 16 | dist: trusty 17 | services: 18 | - docker 19 | compiler: 20 | - gcc 21 | os: 22 | - linux 23 | - osx 24 | 25 | 26 | before_install: 27 | - ./.travis/install.sh 28 | 29 | script: 30 | - ./.travis/run_tests.sh -------------------------------------------------------------------------------- /.travis/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then 4 | brew update 5 | brew install cmake 6 | brew install pkg-config 7 | brew install check 8 | brew install llvm 9 | brew install lcov 10 | export PATH="$PATH:/usr/local/opt/llvm/bin/" 11 | else 12 | sudo apt-get update -y -qq 13 | # Use docker to get LLVM without requiring LLVM's APT server to be online 14 | docker build -t refu -f test/Dockerfile test/ 15 | fi 16 | -------------------------------------------------------------------------------- /.travis/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then 4 | # In macosx we don't currently run coverage 5 | mkdir build && 6 | cd build && 7 | cmake -DTEST=1 .. && 8 | make -j4 && cd .. && 9 | ./test.sh --rfbase --in-travis --travis-job-id ${TRAVIS_JOB_ID} 10 | else 11 | docker run -v `pwd`:/build refu sh -c "mkdir build && cd build && cmake -DCOVERAGE=1 -DTEST=1 .. && make -j4 && cd .. && ./test.sh --rfbase --coverage --in-travis --travis-job-id ${TRAVIS_JOB_ID} " 12 | fi 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0) 2 | 3 | # project name and version should be set after cmake_policy CMP0048 4 | project(refu VERSION "0.5.0") 5 | 6 | add_executable(refu "") 7 | add_subdirectory(rfbase) 8 | if (${TEST}) 9 | add_library(test_refu_helper "") 10 | endif() 11 | 12 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") 13 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/rfbase/cmake/") 14 | include(RFOption) 15 | 16 | include(RFTargetSources) 17 | include(RFRefuConfig) 18 | include(RFProjectConfig) 19 | refu_config(refu) 20 | rf_project_config(refu) 21 | if (${TEST}) 22 | refu_config(test_refu_helper) 23 | rf_project_config(test_refu_helper) 24 | include(RFCoverage) 25 | rf_setup_coverage(test_refu_helper) 26 | endif() 27 | 28 | add_subdirectory(src) 29 | add_subdirectory(lib) 30 | 31 | 32 | if (${TEST}) 33 | add_subdirectory(test) 34 | endif() 35 | 36 | # Print compile definitions in case we want to debug 37 | # could also have called rf_project_config(refu) just like we do for rfbase 38 | get_target_property(REFU_COMPILE_DEFS refu COMPILE_DEFINITIONS) 39 | MESSAGE("refu Compile Definitions: ${REFU_COMPILE_DEFS}") 40 | 41 | 42 | -------------------------------------------------------------------------------- /cmake/CreateGperfHeader.cmake: -------------------------------------------------------------------------------- 1 | # Call to create a gperf hashtable header from a gperf file 2 | # 3 | # Required Arguments: 4 | # 5 | # DIR -- The directory in which the input and output files should be located 6 | # INPUT -- The name of the input .gperf file 7 | # OUTPUT -- The name of the output header file 8 | # 9 | 10 | function(create_gperf_header DIR INPUT OUTPUT) 11 | # Add a fake custom target so that gperf creation always runs 12 | add_custom_target( 13 | gperf_${INPUT}_always_run ALL 14 | DEPENDS ${DIR}/fake.h) 15 | 16 | add_custom_command( 17 | OUTPUT 18 | ${DIR}/fake.h # This is the fake 19 | ${DIR}/${OUTPUT} 20 | PRE_BUILD 21 | COMMAND ${GPERF_EXECUTABLE} -t --output-file=${DIR}/${OUTPUT} ${DIR}/${INPUT} 22 | COMMENT "Generating perfect hash table from ${DIR}/${INPUT}") 23 | endfunction() 24 | -------------------------------------------------------------------------------- /cmake/FindGperf.cmake: -------------------------------------------------------------------------------- 1 | # - Find gperf 2 | # This module looks for gperf. This module defines the 3 | # following values: 4 | # GPERF_EXECUTABLE: the full path to the gperf tool. 5 | # GPERF_FOUND: True if gperf has been found. 6 | 7 | INCLUDE(FindCygwin) 8 | 9 | function(rf_use_gperf TARGET) 10 | 11 | FIND_PROGRAM(GPERF_EXECUTABLE 12 | gperf 13 | ${CYGWIN_INSTALL_PATH}/bin 14 | ) 15 | 16 | # handle the QUIETLY and REQUIRED arguments and set GPERF_FOUND to TRUE if 17 | # all listed variables are TRUE 18 | INCLUDE(FindPackageHandleStandardArgs) 19 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gperf DEFAULT_MSG GPERF_EXECUTABLE) 20 | 21 | # now run the gperf command and figure out the version 22 | execute_process( 23 | COMMAND ${GPERF_EXECUTABLE} "--version" 24 | OUTPUT_VARIABLE GPERF_VERSION_OUTPUT 25 | ) 26 | 27 | string(REGEX MATCH 28 | "GNU gperf ([0-9])\\.([0-9])" 29 | GPERF_VERSION_STRING 30 | ${GPERF_VERSION_OUTPUT} 31 | ) 32 | 33 | # Assert that both major and minor version are parsed. 34 | if((NOT CMAKE_MATCH_1 AND NOT CMAKE_MATCH_1 STREQUAL "0") 35 | OR (NOT CMAKE_MATCH_2 AND NOT CMAKE_MATCH_2 STREQUAL "0")) 36 | message(AUTHOR_WARNING "Error during check for gperf version.") 37 | endif() 38 | 39 | set(GPERF_MAJOR_VERSION ${CMAKE_MATCH_1}) 40 | set(GPERF_MINOR_VERSION ${CMAKE_MATCH_2}) 41 | 42 | target_compile_definitions(${TARGET} PUBLIC "GPERF_MAJOR_VERSION=${GPERF_MAJOR_VERSION}") 43 | target_compile_definitions(${TARGET} PUBLIC "GPERF_MINOR_VERSION=${GPERF_MINOR_VERSION}") 44 | 45 | MARK_AS_ADVANCED(GPERF_EXECUTABLE) 46 | MARK_AS_ADVANCED(GPERF_MAJOR_VERSION) 47 | MARK_AS_ADVANCED(GPERF_MINOR_VERSION) 48 | 49 | message("-- Found Gperf ${GPERF_MAJOR_VERSION}.${GPERF_MINOR_VERSION}") 50 | endfunction() 51 | -------------------------------------------------------------------------------- /cmake/FindGraphViz.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2009 LuaDist. 2 | # Created by Peter Kapec 3 | # Redistribution and use of this file is allowed according to the terms of the MIT license. 4 | # For details see the COPYRIGHT file distributed with LuaDist. 5 | # Note: 6 | # Searching headers and libraries is very simple and is NOT as powerful as scripts 7 | # distributed with CMake, because LuaDist defines directories to search for. 8 | # Everyone is encouraged to contact the author with improvements. Maybe this file 9 | # becomes part of CMake distribution sometimes. 10 | 11 | # - Find GraphViz 12 | # Find the native GraphViz headers and libraries. 13 | # 14 | # GRAPHVIZ_INCLUDE_DIRS - where to find m_apm.h, etc. 15 | # GRAPHVIZ_LIBRARIES - List of libraries when using GraphViz. 16 | # GRAPHVIZ_FOUND - True if GraphViz found. 17 | 18 | # Look for the header file. 19 | FIND_PATH(GRAPHVIZ_INCLUDE_DIR NAMES graphviz/graph.h) 20 | 21 | # Look for the library. 22 | FIND_LIBRARY(GRAPHVIZ_gvc_LIBRARY NAMES gvc ) 23 | FIND_LIBRARY(GRAPHVIZ_graph_LIBRARY NAMES graph ) 24 | FIND_LIBRARY(GRAPHVIZ_cdt_LIBRARY NAMES cdt ) 25 | FIND_LIBRARY(GRAPHVIZ_pathplan_LIBRARY NAMES pathplan ) 26 | 27 | SET(GRAPHVIZ_LIBRARY ${GRAPHVIZ_gvc_LIBRARY} ${GRAPHVIZ_graph_LIBRARY} ${GRAPHVIZ_cdt_LIBRARY} ${GRAPHVIZ_pathplan_LIBRARY}) 28 | 29 | # Handle the QUIETLY and REQUIRED arguments and set GRAPHVIZ_FOUND to TRUE if all listed variables are TRUE. 30 | INCLUDE(FindPackageHandleStandardArgs) 31 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GRAPHVIZ DEFAULT_MSG GRAPHVIZ_LIBRARY GRAPHVIZ_INCLUDE_DIR) 32 | 33 | # Copy the results to the output variables. 34 | IF(GRAPHVIZ_FOUND) 35 | SET(GRAPHVIZ_LIBRARIES ${GRAPHVIZ_LIBRARY}) 36 | SET(GRAPHVIZ_INCLUDE_DIRS ${GRAPHVIZ_INCLUDE_DIR}) 37 | ELSE(GRAPHVIZ_FOUND) 38 | SET(GRAPHVIZ_LIBRARIES) 39 | SET(GRAPHVIZ_INCLUDE_DIRS) 40 | ENDIF(GRAPHVIZ_FOUND) 41 | 42 | MARK_AS_ADVANCED(GRAPHVIZ_INCLUDE_DIRS GRAPHVIZ_LIBRARIES) 43 | -------------------------------------------------------------------------------- /cmake/FindJSON-C.cmake: -------------------------------------------------------------------------------- 1 | # JSON-C_FOUND - true if library and headers were found 2 | # JSON-C_INCLUDE_DIRS - include directories 3 | # JSON-C_LIBRARIES - library directories 4 | 5 | find_package(PkgConfig) 6 | pkg_check_modules(PC_JSON-C QUIET json-c) 7 | 8 | find_path(JSON-C_INCLUDE_DIR json.h 9 | HINTS ${PC_JSON-C_INCLUDEDIR} ${PC_JSON-C_INCLUDE_DIRS} PATH_SUFFIXES json-c json) 10 | 11 | find_library(JSON-C_LIBRARY NAMES json-c libjson-c 12 | HINTS ${PC_JSON-C_LIBDIR} ${PC_JSON-C_LIBRARY_DIRS}) 13 | 14 | set(JSON-C_LIBRARIES ${JSON-C_LIBRARY}) 15 | set(JSON-C_INCLUDE_DIRS ${JSON-C_INCLUDE_DIR}) 16 | 17 | include(FindPackageHandleStandardArgs) 18 | 19 | find_package_handle_standard_args(JSON-C DEFAULT_MSG JSON-C_LIBRARY JSON-C_INCLUDE_DIR) 20 | 21 | mark_as_advanced(JSON-C_INCLUDE_DIR JSON-C_LIBRARY) 22 | -------------------------------------------------------------------------------- /cmake/RFTargetSources.cmake: -------------------------------------------------------------------------------- 1 | # Add sources to multiple targets. Wrapper over target_sources() for multiple targets. 2 | # 3 | # Required Arguments: 4 | # 5 | # TARGETS -- A list of targets to add the sources to 6 | # TYPE -- just as in the target_sources() function 7 | # 8 | # Additional Arguments: 9 | # [source1, source2...] All source files to add to the target 10 | 11 | function(rf_target_sources TARGETS TYPE) 12 | foreach(TARGET ${TARGETS}) 13 | foreach(ARG_NUM RANGE 2 ${ARGC}) 14 | target_sources(${TARGET} ${TYPE} ${ARGV${ARG_NUM}}) 15 | endforeach() 16 | endforeach() 17 | endfunction() 18 | 19 | 20 | # Add sources to two targets, one is the normal target and the other is the test one 21 | # iff the TESTS option is passed 22 | # Required Arguments: 23 | # 24 | # TARGET -- The normal target 25 | # TEST_TARGET -- The test target to add sources to if 26 | # TYPE -- just as in the target_sources() function 27 | # 28 | # Additional Arguments: 29 | # [source1, source2...] All source files to add to the target 30 | function(rf_target_and_test_sources TARGET TEST_TARGET TYPE) 31 | foreach(ARG_NUM RANGE 3 ${ARGC}) 32 | target_sources(${TARGET} ${TYPE} ${ARGV${ARG_NUM}}) 33 | if (${TEST}) 34 | target_sources(${TEST_TARGET} ${TYPE} ${ARGV${ARG_NUM}}) 35 | endif() 36 | endforeach() 37 | endfunction() 38 | -------------------------------------------------------------------------------- /cmake/RFUseLLVM.cmake: -------------------------------------------------------------------------------- 1 | # Find, use and configure LLVM for use with the given target 2 | # 3 | # TARGET -- The target for which to configure LLVM 4 | 5 | function(rf_use_llvm TARGET) 6 | if (APPLE) 7 | set(PATHS_TO_SEARCH "/usr/local/opt/llvm") 8 | endif() 9 | find_package( 10 | LLVM REQUIRED CONFIG 11 | PATHS ${PATHS_TO_SEARCH} 12 | ) 13 | message("LLVM INCLUDES: ${LLVM_INCLUDE_DIRS}") 14 | target_include_directories(${TARGET} PUBLIC ${LLVM_INCLUDE_DIRS}) 15 | message("LLVM DEFS: ${LLVM_DEFINITIONS}") 16 | target_compile_definitions(${TARGET} PUBLIC ${LLVM_DEFINITIONS}) 17 | llvm_map_components_to_libnames(llvm_libs core analysis executionengine interpreter native linker) 18 | target_link_libraries(${TARGET} PUBLIC ${llvm_libs}) 19 | target_link_libraries(${TARGET} PUBLIC stdc++) 20 | target_compile_definitions(${TARGET} PUBLIC "RF_LLVM_VERSION=\"${LLVM_VERSION}\"") 21 | target_compile_definitions(${TARGET} PUBLIC "RF_LLVM_VERSION_MAJOR=${LLVM_VERSION_MAJOR}") 22 | target_compile_definitions(${TARGET} PUBLIC "RF_LLVM_VERSION_MINOR=${LLVM_VERSION_MINOR}") 23 | target_compile_definitions(${TARGET} PUBLIC "RF_LLVM_VERSION_PATCH=${LLVM_VERSION_PATCH}") 24 | message("LLVM LIBS: ${llvm_libs}") 25 | endfunction() 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Refu 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/getting_started.rst: -------------------------------------------------------------------------------- 1 | ############### 2 | Getting Started 3 | ############### 4 | 5 | 6 | TODO 7 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ############# 2 | Refu Language 3 | ############# 4 | 5 | 6 | Refu is a hybrid language with a strong type system based on algebraic data types. 7 | It is designed as a general use programming language with focus on system programming. 8 | 9 | It is statically typed, designed for programming to the interface and has a powerful 10 | module system among other features. 11 | 12 | Useful Links 13 | ============= 14 | 15 | * `Source Code `_ 16 | 17 | * `Gitter Chat `_ 18 | 19 | 20 | 21 | Language Documentation 22 | ======================= 23 | 24 | In the following pages of the documentation we will see an introductory tutorial on Refu, presenting all the features of the language in order and how to use them effectively. 25 | 26 | Furthermore if you want to dive into it is the official specification of 27 | the language check out the :doc:`Language Reference `. 28 | 29 | 30 | Introduction to Refulang 31 | ========================= 32 | .. toctree:: 33 | :maxdepth: 2 34 | 35 | getting_started.rst 36 | 37 | 38 | Language Reference 39 | ================== 40 | .. toctree:: 41 | :maxdepth: 2 42 | 43 | reference.rst 44 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=Refu 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /include/analyzer/analyzer_pass1.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_ANALYZER_PASS1_H 2 | #define LFR_ANALYZER_PASS1_H 3 | 4 | #include 5 | 6 | struct analyzer; 7 | struct ast_node; 8 | struct module; 9 | struct analyzer_traversal_ctx; 10 | 11 | /** 12 | * This is the first pass of the analyzer phase. 13 | * 14 | * Initializes the symbol tables for the nodes where this is needed and also 15 | * populates them with values. Since this is the first pass of the analyzer 16 | * phase this function also changes the ownership of the ast nodes. 17 | * 18 | * Also creates a hash for all identifiers and string literals and adds 19 | * them to global string tables. 20 | * This way they can all be disassociated from the file. 21 | * 22 | * @param a The analyzer handle 23 | * @param mod A pointer to the module object for the first pass. 24 | * We need it for the dependencies modules list 25 | * @return True for success, false otherwise 26 | */ 27 | bool analyzer_first_pass(struct module *mod); 28 | 29 | /** 30 | * A function to to be called for a node while traversing the AST 31 | * during analysis. Switches the traversal context's current symbol table 32 | * to the parent's node symbol table dependin on various condition. 33 | * 34 | * @param n The node the callback is called for 35 | * @param ctx The traversal context 36 | */ 37 | bool analyzer_handle_symbol_table_ascending(struct ast_node *n, 38 | struct analyzer_traversal_ctx *ctx); 39 | 40 | /** 41 | * A function to to be called for a node while traversing the AST 42 | * during analysis. Switches the traversal context's current symbol table to the 43 | * new symbol table of child @c n if it has one and if all conditions are met. 44 | * Also creates a new pattern matching context if we are entering a match 45 | * expression. The destruction of said context is taken care of during the 46 | * end of typechecking phase of a match expression. 47 | * 48 | * @param n The node the callback is called for 49 | * @param ctx The traversal context 50 | */ 51 | bool analyzer_handle_traversal_descending(struct ast_node *n, 52 | struct analyzer_traversal_ctx *ctx); 53 | #endif 54 | -------------------------------------------------------------------------------- /include/analyzer/type_set.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPES_SET_H 2 | #define LFR_TYPES_SET_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct type; 10 | struct rir_type; 11 | struct rf_fixed_memorypool; 12 | 13 | i_INLINE_DECL const void *type_objset_key(const struct type *t) 14 | { 15 | return (const void*)t; 16 | } 17 | 18 | size_t type_objset_hashfn(const struct type *t); 19 | bool type_objset_eqfn(const struct type *t1, 20 | const struct type *t2); 21 | 22 | OBJSET_DEFINE_TYPE(type, 23 | struct type, 24 | type_objset_key, 25 | type_objset_hashfn, 26 | type_objset_eqfn) 27 | 28 | /** 29 | * Check if a type can be converted to any type in the set 30 | * 31 | * @param set The type set in question 32 | * @param type The type to check if can be converted to any other type 33 | * in the set 34 | * @return The type in the set that @a type can be converted to or 35 | * NULL for failure. 36 | */ 37 | struct type *type_objset_has_convertable(const struct rf_objset_type *set, 38 | const struct type *type); 39 | /** 40 | * Check if a type UID has a corresponding type in the set 41 | * 42 | * @param set The set in which to search. 43 | * @param uid The UID to check for an existing type in the set 44 | * @return Either a type that matches this uid or NULL if the set 45 | * does not contain such a type 46 | */ 47 | struct type *type_objset_has_uid(const struct rf_objset_type *set, size_t uid); 48 | 49 | /** 50 | * Check if a type description as a string has a corresponding type in the set 51 | * 52 | * @param set The set in which to search. 53 | * @param desc The string description of a type to check if it already 54 | * exists in the set. The string description has to be 55 | * in the canonical way that type_str() would output it. 56 | */ 57 | struct type *type_objset_has_string(const struct rf_objset_type *set, const struct RFstring *desc); 58 | 59 | void type_objset_destroy(struct rf_objset_type *set, 60 | struct rf_fixed_memorypool *types_pool); 61 | 62 | bool typeset_to_ordered_array(struct rf_objset_type *set, struct arr_types *arr); 63 | 64 | #ifdef RF_OPTION_DEBUG 65 | void type_objset_print(struct rf_objset_type *set); 66 | #endif 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /include/analyzer/typecheck.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_ANALYZER_TYPECHECK_H 2 | #define LFR_ANALYZER_TYPECHECK_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct module; 10 | struct ast_node; 11 | struct type; 12 | struct analyzer_traversal_ctx; 13 | 14 | bool analyzer_typecheck(struct module *m, struct ast_node *n); 15 | /** 16 | * Convenience function to set the type of a node and 17 | * remember last node type during traversal 18 | */ 19 | void traversal_node_set_type(struct ast_node *n, 20 | const struct type *t, 21 | struct analyzer_traversal_ctx *ctx); 22 | #endif 23 | -------------------------------------------------------------------------------- /include/analyzer/typecheck_arr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPECHECK_ARR_H 2 | #define LFR_TYPECHECK_ARR_H 3 | 4 | #include 5 | 6 | struct type; 7 | struct ast_node; 8 | struct analyzer_traversal_ctx; 9 | 10 | enum traversal_cb_res typecheck_bracketlist( 11 | struct ast_node *n, 12 | struct analyzer_traversal_ctx *ctx 13 | ); 14 | 15 | enum traversal_cb_res typecheck_indexaccess( 16 | struct ast_node *n, 17 | struct ast_node *left, 18 | struct ast_node *right, 19 | struct analyzer_traversal_ctx *ctx 20 | ); 21 | 22 | /** 23 | * Adjust the types of an array holding elementary values during assignment. 24 | * 25 | * If the bracket list contains elementary constants of a type different to 26 | * but convertable (if we reach this call they should be convertable) to the 27 | * the left type's array then this function iterates the constants of the 28 | * bracketlist and changes their type. It also changes the final type of 29 | * @a n. 30 | * 31 | * @param n Should be a bracketlist ast node holding elementary types. 32 | * @param tleft The left type of the assignment. Should also be also an 33 | * array type. 34 | */ 35 | void typecheck_adjust_elementary_arr_const_values( 36 | struct ast_node *n, 37 | const struct type *tleft 38 | ); 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/analyzer/typecheck_forexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPECHECK_FOREXPR_H 2 | #define LFR_TYPECHECK_FOREXPR_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | struct analyzer_traversal_ctx; 8 | 9 | bool typecheck_forexpr_descending( 10 | struct ast_node *n, 11 | struct analyzer_traversal_ctx *ctx); 12 | 13 | enum traversal_cb_res typecheck_forexpr_ascending( 14 | struct ast_node *n, 15 | struct analyzer_traversal_ctx *ctx); 16 | 17 | enum traversal_cb_res typecheck_iterable( 18 | struct ast_node *n, 19 | struct analyzer_traversal_ctx *ctx); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/analyzer/typecheck_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPECHECK_FUNCTIONS_H 2 | #define LFR_TYPECHECK_FUNCTIONS_H 3 | 4 | #include 5 | 6 | struct type; 7 | struct ast_node; 8 | struct analyzer_traversal_ctx; 9 | 10 | enum traversal_cb_res typecheck_function_call( 11 | struct ast_node *n, 12 | struct analyzer_traversal_ctx *ctx 13 | ); 14 | 15 | enum traversal_cb_res typecheck_fndecl( 16 | struct ast_node *n, 17 | struct analyzer_traversal_ctx *ctx 18 | ); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/analyzer/typecheck_matchexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPECHECK_MATCHEXPR_H 2 | #define LFR_TYPECHECK_MATCHEXPR_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_node; 8 | struct analyzer_traversal_ctx; 9 | struct symbol_table; 10 | 11 | enum traversal_cb_res typecheck_matchcase(struct ast_node *n, 12 | struct analyzer_traversal_ctx* ctx); 13 | enum traversal_cb_res typecheck_matchexpr(struct ast_node *n, 14 | struct analyzer_traversal_ctx *ctx); 15 | 16 | struct pattern_matching_ctx { 17 | //! A set of types that constitute discovered parts of the type 18 | struct rf_objset_type parts; 19 | //! A set of type parts that have been matched 20 | struct rf_objset_type matched; 21 | //! A pointer to the last type that a case's pattern matched to 22 | const struct type *last_matched_case; 23 | bool match_is_over; 24 | }; 25 | bool pattern_matching_ctx_init(struct pattern_matching_ctx *ctx, 26 | const struct symbol_table *st, 27 | struct ast_node *matchexpr); 28 | void pattern_matching_ctx_deinit(struct pattern_matching_ctx *ctx); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/ast/arr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_ARR_H 2 | #define LFR_AST_ARR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct inplocation_mark; 9 | 10 | struct ast_node *ast_arrspec_create( 11 | const struct inplocation_mark *start, 12 | const struct inplocation_mark *end, 13 | struct arr_ast_nodes *dimensions 14 | ); 15 | 16 | i_INLINE_DECL unsigned int ast_arrspec_dimensions_num(struct ast_node *n) 17 | { 18 | AST_NODE_ASSERT_TYPE(n, AST_ARRAY_SPEC); 19 | return darray_size(n->children); 20 | } 21 | 22 | struct ast_node *ast_bracketlist_create( 23 | const struct inplocation_mark *start, 24 | const struct inplocation_mark *end, 25 | struct ast_node *args 26 | ); 27 | 28 | /** 29 | * Get or create the members of a bracket list. 30 | * 31 | * The first time this function is called the members array is created 32 | * and then all subsequent calls simply return it 33 | * 34 | * @param n The ast bracketlist whose members to get/create 35 | * @return the members array of the bracketlist 36 | */ 37 | struct arr_ast_nodes *ast_bracketlist_members(struct ast_node *n); 38 | 39 | 40 | /** 41 | * A way to iterate a bracketlist's members before typechecking creates 42 | * the array of ast_node members 43 | * 44 | * @param n The bracketlist whose ast nodes to iterate 45 | * @param cb The callback function to call for each bracket list member 46 | * @param user The extra user argument to provide to the callback 47 | */ 48 | i_INLINE_DECL bool ast_bracketlist_foreach_member( 49 | const struct ast_node *n, 50 | exprlist_cb cb, 51 | void *user) 52 | { 53 | AST_NODE_ASSERT_TYPE(n, AST_BRACKET_LIST); 54 | RF_ASSERT( 55 | n->state < AST_NODE_STATE_TYPECHECK_1, 56 | "Do not use this function after typechecking" 57 | ); 58 | struct ast_node *expr = darray_item(n->children, 0); 59 | if (!expr) { 60 | return true; 61 | } 62 | return ast_foreach_expr(expr, cb, user); 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/ast/arr_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_ARRDECLS_H 2 | #define LFR_AST_ARRDECLS_H 3 | 4 | #include 5 | 6 | struct ast_bracketlist { 7 | //! An array of all the members of this bracketlist 8 | //! Populated at the beginning of typechecking. 9 | struct arr_ast_nodes members; 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/ast/block.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_BLOCK_H 2 | #define LFR_AST_BLOCK_H 3 | 4 | #include 5 | struct ast_node *ast_block_create(); 6 | 7 | struct module; 8 | 9 | i_INLINE_DECL bool ast_block_symbol_table_init(struct ast_node *n, 10 | struct module *m) 11 | { 12 | AST_NODE_ASSERT_TYPE(n, AST_BLOCK); 13 | return symbol_table_init(&n->block.st, m); 14 | } 15 | 16 | i_INLINE_DECL struct symbol_table* ast_block_symbol_table_get(struct ast_node *n) 17 | { 18 | AST_NODE_ASSERT_TYPE(n, AST_BLOCK); 19 | return &n->block.st; 20 | } 21 | 22 | i_INLINE_DECL void ast_block_add_element(struct ast_node *n, struct ast_node *element) 23 | { 24 | AST_NODE_ASSERT_TYPE(n, AST_BLOCK); 25 | ast_node_add_child(n, element); 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /include/ast/block_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_BLOCK_DECLS_H 2 | #define LFR_AST_BLOCK_DECLS_H 3 | 4 | struct ast_node; 5 | struct inplocation_mark; 6 | 7 | #include 8 | 9 | struct ast_block { 10 | //! The block's symbol table. Only initialized in the analyzer phase 11 | struct symbol_table st; 12 | }; 13 | #endif 14 | -------------------------------------------------------------------------------- /include/ast/constants_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_CONSTANTS_DECLS_H 2 | #define LFR_AST_CONSTANTS_DECLS_H 3 | 4 | #include 5 | #include 6 | 7 | enum constant_type { 8 | CONSTANT_NUMBER_FLOAT, 9 | CONSTANT_NUMBER_INTEGER, 10 | CONSTANT_BOOLEAN, 11 | }; 12 | 13 | struct ast_constant { 14 | enum constant_type type; 15 | union { 16 | int64_t integer; 17 | double floating; 18 | bool boolean; 19 | } value; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/ast/forexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_FOR_EXPRESSION_H 2 | #define LFR_AST_FOR_EXPRESSION_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | struct ast_node; 11 | struct inplocation_mark; 12 | 13 | struct ast_node *ast_forexpr_create( 14 | const struct inplocation_mark *start, 15 | const struct inplocation_mark *end, 16 | struct ast_node *loopvar, 17 | struct ast_node *iterable, 18 | struct ast_node *body 19 | ); 20 | 21 | i_INLINE_DECL bool ast_forexpr_symbol_table_init(struct ast_node *n, struct module *m) 22 | { 23 | AST_NODE_ASSERT_TYPE(n, AST_FOR_EXPRESSION); 24 | return symbol_table_init(&n->forexpr.st, m); 25 | } 26 | 27 | i_INLINE_DECL struct symbol_table* ast_forexpr_symbol_table_get(struct ast_node *n) 28 | { 29 | AST_NODE_ASSERT_TYPE(n, AST_FOR_EXPRESSION); 30 | return &n->forexpr.st; 31 | } 32 | 33 | i_INLINE_DECL struct ast_node* ast_forexpr_iterable_get(const struct ast_node *n) 34 | { 35 | AST_NODE_ASSERT_TYPE(n, AST_FOR_EXPRESSION); 36 | return n->forexpr.iterable; 37 | } 38 | 39 | i_INLINE_DECL struct ast_node* ast_forexpr_loopvar_get(const struct ast_node *n) 40 | { 41 | AST_NODE_ASSERT_TYPE(n, AST_FOR_EXPRESSION); 42 | return n->forexpr.loopvar; 43 | } 44 | 45 | i_INLINE_DECL struct ast_node* ast_forexpr_body_get(const struct ast_node *n) 46 | { 47 | AST_NODE_ASSERT_TYPE(n, AST_FOR_EXPRESSION); 48 | return n->forexpr.body; 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/ast/forexpr_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_FOR_EXPRESSION_DECLS_H 2 | #define LFR_AST_FOR_EXPRESSION_DECLS_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | struct ast_iterable; 8 | 9 | struct ast_forexpr { 10 | //! The loop variable that changes in each iteration 11 | struct ast_node *loopvar; 12 | //! The iterable object 13 | struct ast_node *iterable; 14 | //! The body of the loop, code to execute in each iteration 15 | struct ast_node *body; 16 | //! Symbol table for the loop variable 17 | struct symbol_table st; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/ast/function_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_FUNCTIONS_DECLS_H 2 | #define LFR_AST_FUNCTIONS_DECLS_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_node; 8 | struct inplocation_mark; 9 | struct type; 10 | 11 | //! The position in the code where a function declaration is found 12 | enum fndecl_position { 13 | FNDECL_STANDALONE, 14 | FNDECL_PARTOF_IMPL, 15 | FNDECL_PARTOF_TYPECLASS, 16 | FNDECL_PARTOF_FOREIGN_IMPORT 17 | }; 18 | 19 | struct ast_fndecl { 20 | //! identifier of the name 21 | struct ast_node *name; 22 | //! Optional: generic declaration 23 | struct ast_node *genr; 24 | //! type description of the arguments 25 | struct ast_node *args; 26 | //! Optional: type description of the return value 27 | struct ast_node *ret; 28 | 29 | //! Position of function declaration. Basically where it's found in the code 30 | enum fndecl_position position; 31 | //! Number of function arguments TODO : remove when rir_function is used instead 32 | unsigned args_num; 33 | 34 | //! Symbol table of the function's arguments and return values. 35 | //! Only initialized in analyzer phase. 36 | //! Not using top level type descriptions with their own symbol tables since 37 | //! having it here makes it easier to combine symbol from both args and return 38 | struct symbol_table st; 39 | }; 40 | 41 | struct ast_fnimpl { 42 | //! The function's declaration (signature) 43 | struct ast_node *decl; 44 | //! The function's body, either a block or a match expression 45 | struct ast_node *body; 46 | //! Symbol table of the function's arguments. 47 | //! Points to the symbol table of the declaration 48 | struct symbol_table *st; 49 | }; 50 | 51 | enum ast_fncall_type { 52 | AST_FNCALL_NORMAL = 0, 53 | //! Set by typecheking if this is an explicit conversion 54 | AST_FNCALL_EXPLICIT_CONVERSION, 55 | //! Set by typechecking if this is a call to a function with sum type args 56 | AST_FNCALL_SUM, 57 | //! Set by typecheking if this is a foreign function call 58 | AST_FNCALL_FOREIGN, 59 | }; 60 | 61 | struct ast_fncall { 62 | //! identifier of the name 63 | struct ast_node *name; 64 | //! Expression describing the function arguments or NULL if there is no arguments 65 | struct ast_node *args; 66 | //! Type that matched this particular function call's parameters 67 | //! during typechecking. 68 | const struct type *params_type; 69 | //! Type of the original function this call refers to. Set during typechecking 70 | const struct type *declared_type; 71 | //! Type of call 72 | enum ast_fncall_type type; 73 | //! An array of all the arguments of this function call 74 | //! Populated at the beginning of typechecking. 75 | struct arr_ast_nodes arguments; 76 | //! Optional: generic attribute 77 | struct ast_node *genr; 78 | }; 79 | #endif 80 | -------------------------------------------------------------------------------- /include/ast/generics.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_GENERICS_H 2 | #define LFR_AST_GENERICS_H 3 | 4 | #include 5 | #include 6 | 7 | struct inplocation_mark; 8 | 9 | /* -- genrtype functions -- */ 10 | 11 | struct ast_node *ast_genrtype_create(struct ast_node *type, struct ast_node *id); 12 | 13 | #include 14 | 15 | i_INLINE_DECL const struct RFstring *ast_genrtype_id_str(struct ast_node *n) 16 | { 17 | AST_NODE_ASSERT_TYPE(n, AST_GENERIC_TYPE); 18 | return ast_identifier_str(n->genrtype.id); 19 | } 20 | 21 | /* -- genrdecl functions -- */ 22 | 23 | struct ast_node *ast_genrdecl_create(const struct inplocation_mark *start, 24 | const struct inplocation_mark *end); 25 | 26 | /** 27 | * Check if an identifier string is a generic type in the declaration 28 | * 29 | * @param n The generic type declaration 30 | * @param id The identifier string to check 31 | * @return The ast node of the generic type if found and NULL otherwise 32 | */ 33 | struct ast_node *ast_genrdecl_string_is_genr(struct ast_node *n, 34 | const struct RFstring *id); 35 | 36 | /* -- genrattr functions -- */ 37 | 38 | struct ast_node *ast_genrattr_create(const struct inplocation_mark *start, 39 | const struct inplocation_mark *end); 40 | #endif 41 | -------------------------------------------------------------------------------- /include/ast/generics_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_GENERICS_DECLS_H 2 | #define LFR_AST_GENERICS_DECLS_H 3 | 4 | struct ast_node; 5 | 6 | struct ast_genrtype { 7 | struct ast_node *type; 8 | struct ast_node *id; 9 | }; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/ast/identifier.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_IDENTIFIER_H 2 | #define LFR_AST_IDENTIFIER_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | struct ast_node; 11 | struct inplocation; 12 | struct inplocation_mark; 13 | struct module; 14 | 15 | struct ast_identifier { 16 | struct RFstring string; 17 | uint32_t hash; 18 | }; 19 | 20 | 21 | /** 22 | * Create a new AST identifier 23 | * 24 | * @param loc The location from which to create the identifier 25 | * @param skip_start The number of chars to skip from the location start 26 | * after which the actual identifier content starts. 27 | * Can be 0. 28 | * @return The allocated identifier. 29 | */ 30 | struct ast_node *ast_identifier_create(struct inplocation *loc, unsigned skip_start); 31 | void ast_identifier_print(struct ast_node *n, int depth); 32 | 33 | /** 34 | * String getter for both an identifier and an xidentifier's string when 35 | * the identifier is still before the first pass of the analysis stage 36 | */ 37 | const struct RFstring *ast_identifier_str(const struct ast_node *n); 38 | 39 | /** 40 | * String getter for both an identifier and an xidentifier's string when 41 | * the identifier has been indexed by the analysis stage 42 | */ 43 | const struct RFstring *ast_identifier_analyzed_str(const struct ast_node *n); 44 | /** 45 | * Returns if the string is '_', which is a wildcard 46 | */ 47 | bool string_is_wildcard(const struct RFstring *s); 48 | /** 49 | * Returns if the identifier is '_', which is a wildcard 50 | */ 51 | bool ast_identifier_is_wildcard(const struct ast_node *n); 52 | 53 | bool ast_identifier_hash_create(struct ast_node *n, struct module *m); 54 | 55 | /* -- xidentifier -- */ 56 | 57 | /** 58 | * An identifier annotated with extra information 59 | */ 60 | struct ast_xidentifier { 61 | struct ast_node *id; 62 | bool is_constant; 63 | struct ast_node *genr; 64 | struct ast_node *arrspec; 65 | }; 66 | 67 | 68 | struct ast_node *ast_xidentifier_create( 69 | const struct inplocation_mark *start, 70 | const struct inplocation_mark *end, 71 | struct ast_node *id, 72 | bool is_constant, 73 | struct ast_node *genr, 74 | struct ast_node *arrspec 75 | ); 76 | 77 | /** 78 | * String getter for only for an xidentifier's string 79 | */ 80 | const struct RFstring *ast_xidentifier_str(const struct ast_node *n); 81 | #endif 82 | -------------------------------------------------------------------------------- /include/ast/ifexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_IF_EXPRESSION_H 2 | #define LFR_AST_IF_EXPRESSION_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | struct ast_node; 11 | struct inplocation_mark; 12 | 13 | struct ast_node *ast_condbranch_create(const struct inplocation_mark *start, 14 | const struct inplocation_mark *end, 15 | struct ast_node *cond, 16 | struct ast_node *body); 17 | 18 | i_INLINE_DECL struct ast_node *ast_condbranch_condition_get(const struct ast_node *n) 19 | { 20 | AST_NODE_ASSERT_TYPE(n, AST_CONDITIONAL_BRANCH); 21 | return n->condbranch.cond; 22 | } 23 | 24 | i_INLINE_DECL struct ast_node *ast_condbranch_body_get(const struct ast_node *n) 25 | { 26 | AST_NODE_ASSERT_TYPE(n, AST_CONDITIONAL_BRANCH); 27 | return n->condbranch.body; 28 | } 29 | 30 | struct ast_node *ast_ifexpr_create(const struct inplocation_mark *start, 31 | const struct inplocation_mark *end, 32 | struct ast_node *taken_branch, 33 | struct ast_node *fall_through_branch); 34 | 35 | i_INLINE_DECL void ast_ifexpr_add_fallthrough_branch(struct ast_node *n, 36 | struct ast_node *branch) 37 | { 38 | RF_ASSERT(n->type == AST_BLOCK || n->type == AST_IF_EXPRESSION, 39 | "Unexpected ast node type"); 40 | ast_node_register_child(n, branch, ifexpr.fallthrough_branch); 41 | } 42 | 43 | i_INLINE_DECL struct ast_node *ast_ifexpr_condition_get(const struct ast_node *ifexpr) 44 | { 45 | AST_NODE_ASSERT_TYPE(ifexpr, AST_IF_EXPRESSION); 46 | return ifexpr->ifexpr.taken_branch->condbranch.cond; 47 | } 48 | 49 | i_INLINE_DECL struct ast_node *ast_ifexpr_taken_block_get(const struct ast_node *ifexpr) 50 | { 51 | AST_NODE_ASSERT_TYPE(ifexpr, AST_IF_EXPRESSION); 52 | return ifexpr->ifexpr.taken_branch->condbranch.body; 53 | } 54 | 55 | i_INLINE_DECL struct ast_node *ast_ifexpr_taken_branch_get(const struct ast_node *ifexpr) 56 | { 57 | AST_NODE_ASSERT_TYPE(ifexpr, AST_IF_EXPRESSION); 58 | return ifexpr->ifexpr.taken_branch; 59 | } 60 | 61 | i_INLINE_DECL struct ast_node *ast_ifexpr_fallthrough_branch_get(const struct ast_node *ifexpr) 62 | { 63 | AST_NODE_ASSERT_TYPE(ifexpr, AST_IF_EXPRESSION); 64 | return ifexpr->ifexpr.fallthrough_branch; 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /include/ast/ifexpr_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_IF_EXPRESSION_DECLS_H 2 | #define LFR_AST_IF_EXPRESSION_DECLS_H 3 | 4 | struct ast_node; 5 | 6 | struct ast_condbranch { 7 | //! An expression containing the condition for this branch 8 | struct ast_node *cond; 9 | //! A block containing the body of the condition 10 | struct ast_node *body; 11 | }; 12 | 13 | struct ast_ifexpr { 14 | //! A conditional branch for the 'if' of the if expression 15 | struct ast_node *taken_branch; 16 | //! The block for the else code. Can be one of: 17 | //! + another ifexpr signifying an elif 18 | //! + a simple block signifying an else 19 | //! + NULL signifying absence of elif/else 20 | struct ast_node *fallthrough_branch; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/ast/iterable.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_ITERABLE_H 2 | #define LFR_AST_ITERABLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct ast_node; 10 | struct inplocation_mark; 11 | 12 | struct ast_node *ast_iterable_create_identifier(struct ast_node *identifier); 13 | 14 | struct ast_node *ast_iterable_create_range( 15 | struct ast_node *start_node, 16 | struct ast_node *step_node, 17 | struct ast_node *end_node 18 | ); 19 | 20 | /** 21 | * Return (if possible) the number of loops the range will create 22 | * @param n The iterable ast node 23 | * @return The number of loops the range will create or -1 if it's not possible 24 | * to determine in compile time. 25 | */ 26 | int64_t ast_iterable_range_number_of_loops(const struct ast_node *n); 27 | 28 | i_INLINE_DECL struct ast_node* ast_iterable_identifier_get(const struct ast_node *n) 29 | { 30 | RF_ASSERT( 31 | n->type == AST_ITERABLE && n->iterable.type == ITERABLE_COLLECTION, 32 | "Illegal ast node type. Expected a collection iterable" 33 | ); 34 | return n->iterable.identifier; 35 | } 36 | 37 | i_INLINE_DECL enum iterable_type ast_iterable_type_get(const struct ast_node *n) 38 | { 39 | AST_NODE_ASSERT_TYPE(n, AST_ITERABLE); 40 | return n->iterable.type; 41 | } 42 | 43 | bool ast_iterable_range_start_get(const struct ast_node *n, int64_t *ret); 44 | bool ast_iterable_range_step_get(const struct ast_node *n, int64_t *ret); 45 | bool ast_iterable_range_end_get(const struct ast_node *n, int64_t *ret); 46 | 47 | bool ast_iterable_range_compiletime_computable( 48 | const struct ast_node *n, 49 | int64_t *start, 50 | int64_t *step, 51 | int64_t* end 52 | ); 53 | 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/ast/iterable_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_ITERABLE_DECLS_H 2 | #define LFR_AST_ITERABLE_DECLS_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | 8 | enum iterable_type { 9 | ITERABLE_COLLECTION = 0, 10 | ITERABLE_RANGE = 1, 11 | }; 12 | 13 | struct int_range { 14 | int64_t start; 15 | int64_t step; 16 | int64_t end; 17 | struct ast_node *start_node; 18 | struct ast_node *step_node; 19 | struct ast_node *end_node; 20 | }; 21 | 22 | struct ast_iterable { 23 | enum iterable_type type; 24 | union { 25 | struct ast_node *identifier; 26 | struct int_range range; 27 | }; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/ast/matchexpr_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_MATCHEXPR_DECLS_H 2 | #define LFR_AST_MATCHEXPR_DECLS_H 3 | 4 | #include 5 | 6 | struct ast_matchcase { 7 | //! A type description of the match pattern 8 | struct ast_node *pattern; 9 | //! An expression to follow when pattern matches 10 | struct ast_node *expression; 11 | //! A pointer to the type that the pattern of this case matched 12 | const struct type *matched_type; 13 | //! The index of matched type in the original type 14 | int match_idx; 15 | //! Symbol table of this matchcase 16 | //! Points to the symbol table of the matchcase pattern 17 | struct symbol_table *st; 18 | }; 19 | 20 | struct ast_matchexpr { 21 | //! A pointer to either the identifier of the match node 22 | //! or to the arguments of the parent function if this is 23 | //! a headless match expression 24 | struct ast_node *identifier_or_fnargtype; 25 | //! The type that the match expression tries to match 26 | const struct type *matching_type; 27 | //! Number of match cases under the expression 28 | size_t match_cases_num; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/ast/module.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_MODULE_H 2 | #define LFR_AST_MODULE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | struct ast_node; 11 | struct inplocation_mark; 12 | /* -- ast import functions -- */ 13 | struct ast_node *ast_import_create(const struct inplocation_mark *start, 14 | const struct inplocation_mark *end, 15 | bool foreign); 16 | 17 | i_INLINE_DECL bool ast_import_is_foreign(const struct ast_node *n) 18 | { 19 | AST_NODE_ASSERT_TYPE(n, AST_IMPORT); 20 | return n->import.foreign; 21 | } 22 | 23 | i_INLINE_DECL bool ast_node_is_foreign_import(const struct ast_node *n) 24 | { 25 | 26 | return n->type == AST_IMPORT && n->import.foreign; 27 | } 28 | 29 | /* -- ast module functions -- */ 30 | struct ast_node *ast_module_create(const struct inplocation_mark *start, 31 | const struct inplocation_mark *end, 32 | struct ast_node *name, 33 | struct ast_node *args); 34 | 35 | i_INLINE_DECL struct symbol_table *ast_module_symbol_table_get(struct ast_node *n) 36 | { 37 | AST_NODE_ASSERT_TYPE(n, AST_MODULE); 38 | return &n->module.st; 39 | } 40 | 41 | i_INLINE_DECL const struct RFstring *ast_module_name(const struct ast_node *n) 42 | { 43 | AST_NODE_ASSERT_TYPE(n, AST_MODULE); 44 | return ast_identifier_str(n->module.name); 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /include/ast/module_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_MODULE_DECLS_H 2 | #define LFR_AST_MODULE_DECLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct ast_node; 9 | 10 | struct ast_import { 11 | //! Distinguish between foreign and normal imports 12 | bool foreign; 13 | //! Array of the importees 14 | struct arr_ast_nodes member; 15 | }; 16 | 17 | struct ast_module { 18 | //! Identifier with the name of the module 19 | struct ast_node *name; 20 | //! If the module has arguments, this contains their type description. If not NULL. 21 | struct ast_node *args; 22 | //! Symbol table of the module's arguments and of its contents 23 | struct symbol_table st; 24 | }; 25 | #endif 26 | -------------------------------------------------------------------------------- /include/ast/operators_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_OPERATORS_DECLS_H 2 | #define LFR_AST_OPERATORS_DECLS_H 3 | 4 | struct ast_node; 5 | struct type; 6 | 7 | enum binaryop_type { 8 | BINARYOP_ADD, 9 | BINARYOP_SUB, 10 | BINARYOP_MUL, 11 | BINARYOP_DIV, 12 | 13 | BINARYOP_CMP_EQ, 14 | BINARYOP_CMP_NEQ, 15 | BINARYOP_CMP_GT, 16 | BINARYOP_CMP_GTEQ, 17 | BINARYOP_CMP_LT, 18 | BINARYOP_CMP_LTEQ, 19 | 20 | BINARYOP_LOGIC_AND, 21 | BINARYOP_LOGIC_OR, 22 | 23 | BINARYOP_INDEX_ACCESS, 24 | BINARYOP_MEMBER_ACCESS, 25 | 26 | BINARYOP_BITWISE_OR, 27 | BINARYOP_BITWISE_AND, 28 | BINARYOP_BITWISE_XOR, 29 | 30 | BINARYOP_ASSIGN, 31 | BINARYOP_COMMA 32 | }; 33 | 34 | struct ast_binaryop { 35 | //! The type of binary operation performed 36 | enum binaryop_type type; 37 | //! The left opeand ast node 38 | struct ast_node *left; 39 | //! The right operand ast node 40 | struct ast_node *right; 41 | //! [Optional] May only exist after typechecking 42 | //! The common type to which both operands can be typecast in the backend 43 | const struct type *common_type; 44 | }; 45 | 46 | enum unaryop_type { 47 | UNARYOP_AMPERSAND, 48 | UNARYOP_INC, 49 | UNARYOP_DEC, 50 | UNARYOP_MINUS, 51 | UNARYOP_PLUS, 52 | }; 53 | 54 | struct ast_unaryop { 55 | enum unaryop_type type; 56 | struct ast_node *operand; 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/ast/returnstmt.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_RETURNSTMT_H 2 | #define LFR_AST_RETURNSTMT_H 3 | 4 | #include 5 | 6 | struct ast_node *ast_returnstmt_create(const struct inplocation_mark *start, 7 | const struct inplocation_mark *end, 8 | struct ast_node *expr); 9 | 10 | i_INLINE_DECL struct ast_node *ast_returnstmt_expr_get(const struct ast_node *n) 11 | { 12 | AST_NODE_ASSERT_TYPE(n, AST_RETURN_STATEMENT); 13 | return n->returnstmt.expr; 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /include/ast/returnstmt_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_RETURNSTMT_DECLS_H 2 | #define LFR_AST_RETURNSTMT_DECLS_H 3 | 4 | struct ast_node; 5 | 6 | struct ast_returnstmt { 7 | //! The expression to return 8 | struct ast_node *expr; 9 | }; 10 | #endif 11 | -------------------------------------------------------------------------------- /include/ast/string_literal.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_STRING_LITERAL_H 2 | #define LFR_AST_STRING_LITERAL_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct ast_node; 10 | struct inplocation; 11 | struct module; 12 | 13 | struct ast_node *ast_string_literal_create(struct inplocation *loc); 14 | bool ast_string_literal_hash_create(struct ast_node *lit, struct module *m); 15 | 16 | #include 17 | i_INLINE_DECL const struct RFstring * 18 | ast_string_literal_get_str(const struct ast_node *lit) 19 | { 20 | AST_NODE_ASSERT_TYPE(lit, AST_STRING_LITERAL); 21 | return &lit->string_literal.string; 22 | } 23 | 24 | i_INLINE_DECL uint32_t ast_string_literal_get_hash(const struct ast_node *lit) 25 | { 26 | AST_NODE_ASSERT_TYPE(lit, AST_STRING_LITERAL); 27 | return lit->string_literal.hash; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/ast/string_literal_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_STRING_LITERAL_DECLS_H 2 | #define LFR_AST_STRING_LITERAL_DECLS_H 3 | 4 | #include 5 | 6 | struct ast_string_literal { 7 | struct RFstring string; 8 | uint32_t hash; 9 | }; 10 | #endif 11 | -------------------------------------------------------------------------------- /include/ast/type_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_TYPE_DECLS_H 2 | #define LFR_AST_TYPE_DECLS_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_node; 8 | 9 | struct ast_typeop { 10 | //! Type Operator type 11 | enum typeop_type type; 12 | struct ast_node *left; 13 | struct ast_node *right; 14 | }; 15 | 16 | /** 17 | * Top level description of a type 18 | */ 19 | struct ast_typedesc { 20 | struct ast_node *desc; 21 | //! Symbol table of the identifiers inside the type declaration 22 | struct symbol_table st; 23 | }; 24 | 25 | struct ast_typeleaf { 26 | struct ast_node *left; 27 | struct ast_node *right; 28 | }; 29 | 30 | struct ast_typedecl { 31 | //! identifier of the name 32 | struct ast_node *name; 33 | //! Data description 34 | struct ast_node *desc; 35 | //! Optional, generic declaration 36 | //! TODO: This is not yet implemented! 37 | struct ast_node *genrdecl; 38 | }; 39 | #endif 40 | -------------------------------------------------------------------------------- /include/ast/typeclass.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_TYPECLASS_H 2 | #define LFR_AST_TYPECLASS_H 3 | 4 | struct ast_node; 5 | struct inplocation_mark; 6 | 7 | struct ast_node *ast_typeclass_create(const struct inplocation_mark *start, 8 | const struct inplocation_mark *end, 9 | struct ast_node *name, 10 | struct ast_node *genr); 11 | 12 | struct ast_node *ast_typeinstance_create(const struct inplocation_mark *start, 13 | const struct inplocation_mark *end, 14 | struct ast_node *class_name, 15 | struct ast_node *type_name, 16 | struct ast_node *genr); 17 | #endif 18 | -------------------------------------------------------------------------------- /include/ast/typeclass_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_TYPECLASS_DECLS_H 2 | #define LFR_AST_TYPECLASS_DECLS_H 3 | 4 | struct ast_typeclass { 5 | struct ast_node *name; 6 | struct ast_node *generics; 7 | }; 8 | 9 | struct ast_typeinstance { 10 | struct ast_node *class_name; 11 | struct ast_node *type_name; 12 | struct ast_node *generics; 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/ast/vardecl.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_VARDECL_H 2 | #define LFR_AST_VARDECL_H 3 | 4 | struct ast_node; 5 | struct inplocation_mark; 6 | 7 | struct ast_node *ast_vardecl_create( 8 | const struct inplocation_mark *start, 9 | const struct inplocation_mark *end, 10 | struct ast_node *leaf 11 | ); 12 | 13 | #include 14 | #include 15 | 16 | i_INLINE_DECL struct ast_node *ast_vardecl_desc_get(const struct ast_node *n) 17 | { 18 | AST_NODE_ASSERT_TYPE(n, AST_VARIABLE_DECLARATION); 19 | return n->vardecl.leaf; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /include/ast/vardecl_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_AST_VARDECL_DECLS_H 2 | #define LFR_AST_VARDECL_DECLS_H 3 | 4 | struct ast_node; 5 | 6 | struct ast_vardecl { 7 | //! Type leaf of the type description 8 | struct ast_node *leaf; 9 | }; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/backend/llvm.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_H 2 | #define LFR_BACKEND_LLVM_H 3 | 4 | #include 5 | 6 | struct RFilist_head; 7 | struct compiler_args; 8 | struct modules_arr; 9 | 10 | 11 | /** 12 | * Generate the backend code with llvm 13 | * 14 | * @param fronts_list A list of front_ctxs to try and compile 15 | * @param args The arguments given to the compiler 16 | * 17 | * @return true in succes and false for failure 18 | */ 19 | bool bllvm_generate(struct modules_arr *modules, struct compiler_args *args); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/info/msg.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_INFO_MSG_H 2 | #define LFR_INFO_MSG_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define MSG_COORD_STR_BUFF 128 11 | 12 | struct info_msg { 13 | //! The actual message string 14 | struct RFstring s; 15 | //! Can attach the message to a list 16 | RFilist_node ln; 17 | //! The type of the message. Either warning or error for now. 18 | enum info_msg_type type; 19 | //! The start mark to put for the error 20 | struct inplocation_mark start_mark; 21 | //! The end mark to put for the error 22 | struct inplocation_mark end_mark; 23 | }; 24 | 25 | i_INLINE_DECL bool info_msg_has_end_mark(struct info_msg *msg) 26 | { 27 | return msg->end_mark.p != NULL; 28 | } 29 | 30 | struct info_msg *info_msg_create(enum info_msg_type type, 31 | const struct inplocation_mark *start, 32 | const struct inplocation_mark *end, 33 | const char *fmt, 34 | va_list args); 35 | void info_msg_destroy(struct info_msg *m); 36 | void info_msg_print(struct info_msg *m, FILE *f, struct inpfile *input_file); 37 | 38 | bool info_msg_get_formatted(struct info_msg *m, struct RFstringx *s, 39 | struct inpfile *input_file); 40 | 41 | const struct RFstring *info_msg_type_to_str(enum info_msg_type type); 42 | #endif 43 | -------------------------------------------------------------------------------- /include/inpoffset.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_INPOFFSET_H 2 | #define LFR_INPOFFSET_H 3 | 4 | #include 5 | 6 | struct inpoffset { 7 | unsigned int bytes_moved; 8 | unsigned int chars_moved; 9 | unsigned int lines_moved; 10 | }; 11 | 12 | 13 | #define INPOFFSET_STATIC_INIT() {0, 0, 0} 14 | i_INLINE_DECL void inpoffset_init(struct inpoffset *off) 15 | { 16 | off->bytes_moved = 0; 17 | off->chars_moved = 0; 18 | off->lines_moved = 0; 19 | } 20 | 21 | i_INLINE_DECL void inpoffset_copy(struct inpoffset *dst, 22 | struct inpoffset *src) 23 | { 24 | dst->bytes_moved = src->bytes_moved; 25 | dst->chars_moved = src->chars_moved; 26 | dst->lines_moved = src->lines_moved; 27 | } 28 | 29 | i_INLINE_DECL void inpoffset_add(struct inpoffset *o1, 30 | struct inpoffset *o2) 31 | { 32 | o1->bytes_moved += o2->bytes_moved; 33 | o1->chars_moved += o2->chars_moved; 34 | o1->lines_moved += o2->lines_moved; 35 | } 36 | 37 | i_INLINE_DECL void inpoffset_sub(struct inpoffset *o1, 38 | struct inpoffset *o2) 39 | { 40 | o1->bytes_moved -= o2->bytes_moved; 41 | o1->chars_moved -= o2->chars_moved; 42 | o1->lines_moved -= o2->lines_moved; 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /include/inpstr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_INPSTRING_H 2 | #define LFR_INPSTRING_H 3 | 4 | #include 5 | #include 6 | 7 | struct inpstr { 8 | struct RFstringx str; 9 | uint32_t lines_num; 10 | uint32_t *lines; 11 | }; 12 | 13 | /** 14 | * Initializes an input string from an RFstringx and some lines meta 15 | * information. 16 | * 17 | * @param s The string to initialize 18 | * @param input_str The RFstringx to initialize from. 19 | * We do a shallow copy of @c input_str 20 | * but also owns the memory of the string. Once intialized 21 | * it will manage the memory of input_str. 22 | * @param arr The RFarray containing the lines information. 23 | * Indexing starts from 0 and contains the byte position 24 | * in @c input_str of each new line beginning. Its contents 25 | * will be copied inside the parser string. Can be freed 26 | * after string initialization 27 | * @param lines_num The size of the @c arr in lines 28 | * 29 | * @return True/false in case of success/failure to initialize 30 | */ 31 | bool inpstr_init(struct inpstr *s, 32 | struct RFstringx *input_str, 33 | struct RFarray *arr, 34 | unsigned int lines_num); 35 | 36 | /** 37 | * Initializes an input string from a source string. The source string is copied 38 | * inside the inpstr struct. 39 | */ 40 | bool inpstr_init_from_source(struct inpstr *s, 41 | const struct RFstring *input_str); 42 | 43 | void inpstr_deinit(struct inpstr *s); 44 | 45 | /** 46 | * Obtain a line and column position from a byte pointer 47 | * of an input string 48 | * 49 | * @param s The input string from which to obtain the position. 50 | * @param p The byte pointer inside the string whose line and 51 | * column to retrieve 52 | * @param line[out] Returns the line pointed to by the byte pointer 53 | * @param column[out] Returns the column pointed to by the byte pointer 54 | * 55 | * @return True if the byte pointer represents a valid position 56 | * and false if not 57 | */ 58 | bool inpstr_ptr_to_linecol(struct inpstr *s, 59 | char *p, unsigned int *line, 60 | unsigned int *col); 61 | 62 | i_INLINE_DECL struct RFstringx *inpstr_str(struct inpstr *s) 63 | { 64 | return &s->str; 65 | } 66 | 67 | i_INLINE_DECL char *inpstr_data(struct inpstr *s) 68 | { 69 | return rf_string_data(&s->str); 70 | } 71 | 72 | i_INLINE_DECL char *inpstr_beg(const struct inpstr *s) 73 | { 74 | return rf_string_data(&s->str) - s->str.bIndex; 75 | } 76 | 77 | i_INLINE_DECL uint32_t inpstr_len_from_beg(struct inpstr *s) 78 | { 79 | return rf_string_length_bytes(&s->str) + s->str.bIndex; 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /include/ir/parser/rirtoken.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_RIR_TOKEN_H 2 | #define LFR_RIR_TOKEN_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | struct RFstring; 11 | struct rinternal_token; 12 | 13 | /** 14 | * The tokens of the language 15 | * 16 | * Note that the groups they are grouped in are not necessarily 17 | * correct. For example some tokens can be both binary and unary operators. 18 | * For correct checking of whethere a token belongs to a certain group we have 19 | * the family of TOKEN_IS_XX macros. For example: 20 | * 21 | * TOKEN_IS_BINARY_OP() 22 | * TOKEN_IS_UNARY_OP() 23 | * TOKEN_IS_NUMERIC_CONSTANT() 24 | */ 25 | enum rir_token_type { 26 | RIR_TOK_IDENTIFIER = 0, 27 | RIR_TOK_CONTANT_INTEGER, 28 | RIR_TOK_CONSTANT_FLOAT, 29 | RIR_TOK_STRING_LITERAL, 30 | 31 | RIR_TOK_SM_OCBRACE, 32 | RIR_TOK_SM_CCBRACE, 33 | RIR_TOK_SM_OSBRACE, 34 | RIR_TOK_SM_CSBRACE, 35 | RIR_TOK_SM_OPAREN, 36 | RIR_TOK_SM_CPAREN, 37 | RIR_TOK_SM_DBLQUOTE, 38 | RIR_TOK_SM_COMMA, 39 | 40 | RIR_TOK_OP_MINUS, 41 | RIR_TOK_OP_MULTI, 42 | RIR_TOK_OP_ASSIGN, 43 | 44 | RIR_TOK_SEMICOLON, 45 | 46 | RIR_TOK_GLOBAL, 47 | RIR_TOK_UNIONDEF, 48 | RIR_TOK_TYPEDEF, 49 | RIR_TOK_FNDEF, 50 | RIR_TOK_FNDECL, 51 | RIR_TOK_IDENTIFIER_VARIABLE, 52 | RIR_TOK_IDENTIFIER_LABEL, 53 | RIR_TOK_RETURN, 54 | RIR_TOK_BRANCH, 55 | RIR_TOK_CONDBRANCH, 56 | RIR_TOK_CONVERT, 57 | RIR_TOK_WRITE, 58 | RIR_TOK_READ, 59 | RIR_TOK_CALL, 60 | 61 | RIR_TOK_ADD, 62 | RIR_TOK_SUB, 63 | RIR_TOK_MUL, 64 | RIR_TOK_DIV, 65 | RIR_TOK_CMPEQ, 66 | RIR_TOK_CMPNE, 67 | RIR_TOK_CMPGT, 68 | RIR_TOK_CMPGE, 69 | RIR_TOK_CMPLT, 70 | RIR_TOK_CMPLE, 71 | 72 | RIR_TOKENS_MAX 73 | }; 74 | 75 | /** 76 | * Convenience macro to convert from a normal to rir token type and 77 | * help us avoid writting out the cast each time when using a token 78 | */ 79 | #define rir_toktype(i_tok_) ((enum rir_token_type)(i_tok_)->type) 80 | 81 | 82 | const struct rinternal_token *rir_lexer_lexeme_is_token( 83 | register const char *str, 84 | #if GPERF_MAJOR_VERSION >= 3 && GPERF_MINOR_VERSION >= 1 85 | register size_t len 86 | #else 87 | register unsigned int len 88 | #endif 89 | ); 90 | 91 | const struct RFstring *rir_tokentype_to_str(enum rir_token_type type); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /include/ir/rir_argument.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_ARGUMENT_H 2 | #define LFR_IR_ARGUMENT_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct rirtostr_ctx; 14 | struct type; 15 | struct rir; 16 | 17 | struct rir_type_arr {darray(struct rir_type*);}; 18 | 19 | /** 20 | * Turns a type to a rir type array 21 | * 22 | * @param type The type to turn into a rir type array 23 | * @param arr The rir type array to create 24 | * @param loc The code location of the type creation. Used to 25 | * specify where the array is going to be used 26 | * @param ctx The rir context 27 | * @return true for success 28 | */ 29 | bool rir_typearr_from_type( 30 | struct rir_type_arr *arr, 31 | const struct type *type, 32 | enum rir_code_loc loc, 33 | struct rir_ctx *ctx 34 | ); 35 | bool rir_typearr_tostring(struct rirtostr_ctx *ctx, const struct rir_type_arr *arr); 36 | bool rir_typearr_equal(const struct rir_type_arr *arr1, const struct rir_type_arr *arr2); 37 | 38 | /** 39 | * Frees a type array 40 | * 41 | * @param arr The rir type array to free 42 | * @param r The rir context or NULL. If the rir context is given 43 | * then also the types of the array are individually freed 44 | * since then the function has access to the memory pool 45 | */ 46 | void rir_typearr_deinit(struct rir_type_arr *arr, struct rir *r); 47 | #endif 48 | -------------------------------------------------------------------------------- /include/ir/rir_array.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_ARRAY_H 2 | #define LFR_IR_RIR_ARRAY_H 3 | 4 | #include 5 | 6 | struct rirtostr_ctx; 7 | struct rir_expression; 8 | struct rir_fixedarr; 9 | struct rir_value; 10 | struct rir_ctx; 11 | struct ast_node; 12 | 13 | bool rir_process_bracketlist(const struct ast_node *n, struct rir_ctx *ctx); 14 | bool rir_fixedarr_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *e); 15 | void rir_fixedarr_deinit(struct rir_fixedarr *arr); 16 | 17 | struct rir_object *rir_fixedarrsize_create(struct rir_value *v, struct rir_ctx *ctx); 18 | bool rir_fixedarrsize_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *e); 19 | #endif 20 | -------------------------------------------------------------------------------- /include/ir/rir_binaryop.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_BINARYOP_H 2 | #define LFR_IR_RIR_BINARYOP_H 3 | 4 | #include 5 | 6 | 7 | struct ast_binaryop; 8 | 9 | struct rir_expression *rir_binaryop_create( 10 | const struct ast_binaryop *op, 11 | const struct rir_value *a, 12 | const struct rir_value *b, 13 | enum rir_pos pos, 14 | rir_data data 15 | ); 16 | 17 | struct rir_object *rir_binaryop_create_nonast_obj( 18 | enum rir_expression_type type, 19 | const struct rir_value *a, 20 | const struct rir_value *b, 21 | enum rir_pos pos, 22 | rir_data data 23 | ); 24 | 25 | struct rir_expression *rir_binaryop_create_nonast( 26 | enum rir_expression_type type, 27 | const struct rir_value *a, 28 | const struct rir_value *b, 29 | enum rir_pos pos, 30 | rir_data data 31 | ); 32 | 33 | bool rir_process_binaryop(const struct ast_binaryop *n, struct rir_ctx *ctx); 34 | bool rir_binaryop_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *e); 35 | const struct RFstring *rir_binaryoptype_string(enum rir_expression_type type); 36 | #endif 37 | -------------------------------------------------------------------------------- /include/ir/rir_branch.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_BRANCH_H 2 | #define LFR_IR_RIR_BRANCH_H 3 | 4 | #include 5 | 6 | struct rirtostr_ctx; 7 | struct rir_block; 8 | struct rir_expression; 9 | 10 | struct rir_branch { 11 | struct rir_value *dst; 12 | }; 13 | 14 | bool rir_branch_init(struct rir_branch *b, struct rir_value *dst); 15 | struct rir_branch *rir_branch_create(struct rir_value *dst); 16 | 17 | void rir_branch_deinit(struct rir_branch *b); 18 | void rir_branch_destroy(struct rir_branch *b); 19 | 20 | bool rir_branch_tostring(struct rirtostr_ctx *ctx, const struct rir_branch *b); 21 | 22 | struct rir_condbranch { 23 | const struct rir_value *cond; 24 | struct rir_value *taken; 25 | struct rir_value *fallthrough; 26 | }; 27 | 28 | bool rir_condbranch_init(struct rir_condbranch *b, 29 | const struct rir_value *cond, 30 | struct rir_value *taken, 31 | struct rir_value *fallthrough); 32 | struct rir_condbranch *rir_condbranch_create(const struct rir_value *cond, 33 | struct rir_value *taken, 34 | struct rir_value *fallthrough); 35 | void rir_condbranch_deinit(struct rir_condbranch *b); 36 | void rir_condbranch_destroy(struct rir_condbranch *b); 37 | bool rir_condbranch_tostring(struct rirtostr_ctx *ctx, const struct rir_condbranch *b); 38 | #endif 39 | -------------------------------------------------------------------------------- /include/ir/rir_call.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_CALL_H 2 | #define LFR_IR_CALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct ast_node; 9 | struct rir_value; 10 | struct value_arr; 11 | struct rir_call; 12 | struct rir_expression; 13 | struct rir_ctx; 14 | struct rir_common; 15 | struct rirtostr_ctx; 16 | struct RFstring; 17 | 18 | struct rir_object *rir_call_create_obj_from_ast(const struct ast_node *n, struct rir_ctx *ctx); 19 | struct rir_object *rir_call_create_obj( 20 | const struct RFstring *name, 21 | struct value_arr *args, 22 | bool is_foreign, 23 | enum rir_pos pos, 24 | rir_data data 25 | ); 26 | bool rir_call_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *call); 27 | bool rir_process_fncall(const struct ast_node *n, struct rir_ctx *ctx); 28 | 29 | struct rir_expression *rir_call_to_expr(const struct rir_call *c); 30 | /** 31 | * Get return type from a rir call 32 | * 33 | * @param c The rir call whose return type to get 34 | * @param cm The rir common data 35 | * @return The return type of @a c 36 | */ 37 | struct rir_type *rir_call_return_type(struct rir_call *c, struct rir_common *cm); 38 | 39 | void rir_call_deinit(struct rir_call *c); 40 | #endif 41 | -------------------------------------------------------------------------------- /include/ir/rir_common.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_COMMON_H 2 | #define LFR_IR_RIR_COMMON_H 3 | 4 | #include 5 | 6 | struct rir; 7 | struct rir_fndef; 8 | struct rir_block; 9 | struct rir_expression; 10 | 11 | /** 12 | * Common data required by both ast and parsing rir code 13 | */ 14 | struct rir_common { 15 | struct rir *rir; 16 | struct rir_fndef *current_fn; 17 | struct rir_block *current_block; 18 | }; 19 | 20 | /** 21 | * The rir data. If @a pos: 22 | * + RIRPOS_AST -> then this is rir_ctx 23 | * + RIRPOS_PARSE -> then this is rir_pctx 24 | */ 25 | typedef void* rir_data; 26 | 27 | 28 | void rir_common_block_add(struct rir_common *c, struct rir_expression *expr); 29 | 30 | 31 | /** 32 | * Convenience macros to get rir common members out of rir_data 33 | * 34 | * @warning Kind of a hack, we rely on rir_common 35 | * being first member of rir_ctx and rir_pctx 36 | */ 37 | #define rir_data_common(i_data) \ 38 | ((struct rir_common*)i_data) 39 | 40 | #define rir_data_rir(i_data) \ 41 | ((struct rir_common*)i_data)->rir 42 | 43 | #define rir_data_curr_fn(i_data) \ 44 | ((struct rir_common*)i_data)->current_fn 45 | 46 | #define rir_data_curr_block(i_data) \ 47 | ((struct rir_common*)i_data)->current_block 48 | 49 | #define rir_data_block_add(i_data, i_expr) \ 50 | rir_common_block_add((struct rir_common*)i_data, i_expr) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/ir/rir_constant.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_CONSTANT_H 2 | #define LFR_IR_RIR_CONSTANT_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_node; 8 | struct rir_expression; 9 | struct rir_value; 10 | struct rir_ctx; 11 | struct rir; 12 | struct rirtostr_ctx; 13 | 14 | struct rir_object *rir_constant_create_obj(const struct ast_node *c, struct rir_ctx *ctx); 15 | struct rir_expression *rir_constant_create(const struct ast_node *c, struct rir_ctx *ctx); 16 | /** 17 | * Create a rir constant value from an int64 18 | * 19 | * Creates a value that is not meant to belong to any specific rir object. As 20 | * such the value will also be stored under the given rir module so that it can 21 | * later be freed. 22 | * 23 | * @param n The integer to create the constant from 24 | * @param r The rir module object under which the value will be stored. 25 | * @return A pointer to the allocated value 26 | */ 27 | struct rir_value *rir_constantval_create_fromint64(int64_t n, struct rir* r); 28 | bool rir_constantval_init_fromint64(struct rir_value *v, struct rir *r, int64_t n); 29 | 30 | struct rir_value *rir_constantval_create_fromint32(int32_t n, struct rir* r); 31 | bool rir_constantval_init_fromint32(struct rir_value *v, struct rir *r, int32_t n); 32 | 33 | const struct RFstring *rir_constant_string(const struct rir_value *val); 34 | bool rir_constant_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *e); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/ir/rir_convert.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_CONVERT_H 2 | #define LFR_IR_RIR_CONVERT_H 3 | 4 | #include 5 | #include 6 | 7 | struct rir_expression; 8 | struct rir_value; 9 | struct rir_type; 10 | struct rir_ctx; 11 | struct ast_node; 12 | 13 | struct rir_object *rir_convert_create_obj( 14 | const struct rir_value *convval, 15 | const struct rir_type *totype, 16 | enum rir_pos pos, 17 | rir_data data 18 | ); 19 | 20 | bool rir_process_convertcall(const struct ast_node *n, struct rir_ctx *ctx); 21 | 22 | /** 23 | * Check if a value is of a specific type and if not do a conversion 24 | * 25 | * @param val The value to check 26 | * @param checktype The type to check for equality with val's type 27 | * @param pos Denotes which code module the function is called from. 28 | * @return If the passed value's type is equal to @a checktype 29 | * then @a val itself is returned. If not and iff 30 | * pos == RIRPOS_AST a conversion instruction is added 31 | * and the conversion's value is returned. The new 32 | * instruction gets a copy of @a checktype for its type. 33 | */ 34 | const struct rir_value *rir_maybe_convert( 35 | const struct rir_value *val, 36 | const struct rir_type *checktype, 37 | enum rir_pos pos, 38 | rir_data data 39 | ); 40 | 41 | /** 42 | * Creates a convert object and adds it to the current block if the returned 43 | * object was a rir expression. 44 | * 45 | * @param convval The value for conversion 46 | * @param totype The type to convert to 47 | * @param pos Denotes which code module the function is called from. 48 | * @return A rir object representing the conversion. It's 49 | * either a rir expression in which case it's a 50 | * convert() rir instruction or a rir global since 51 | * conversion was done at compile time. Null in error. 52 | */ 53 | struct rir_object *rir_convert_create_obj_maybeadd( 54 | const struct rir_value *convval, 55 | const struct rir_type *totype, 56 | enum rir_pos pos, 57 | rir_data data 58 | ); 59 | #endif 60 | -------------------------------------------------------------------------------- /include/ir/rir_global.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_GLOBAL_H 2 | #define LFR_IR_RIR_GLOBAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // TODO: Rir global could be renamed to something else ...? 9 | 10 | struct rirtostr_ctx; 11 | struct rir_parser; 12 | 13 | //! A global variable declaration for a module 14 | struct rir_global { 15 | //! The value of the variable 16 | struct rir_value val; 17 | }; 18 | 19 | struct rir_object *rir_global_create_string(const struct rir_type *type, 20 | const struct RFstring *name, 21 | const void *value, 22 | struct rir *rir); 23 | 24 | struct rir_object *rir_global_create_parsed(struct rir_parser *p, 25 | const struct RFstring *name, 26 | const struct ast_node *type, 27 | const struct ast_node *value); 28 | 29 | void rir_global_deinit(struct rir_global *global); 30 | bool rir_global_tostring(struct rirtostr_ctx *ctx, const struct rir_global *g); 31 | 32 | i_INLINE_DECL const struct RFstring *rir_global_name(const struct rir_global *g) 33 | { 34 | return &g->val.id; 35 | } 36 | 37 | i_INLINE_DECL struct rir_type *rir_global_type(const struct rir_global *g) 38 | { 39 | return g->val.type; 40 | } 41 | 42 | /** 43 | * Add or retrieve a global string literal object 44 | * 45 | * @param rir The rir object to work with 46 | * @param s The string for which to check if there is a global string 47 | * object in the map and if not to create a map entry. A copy 48 | * of the string is kept inside the global string literal 49 | * object 50 | * @return Either the newly created object or the retrieved object. 51 | * NULL in failure 52 | */ 53 | struct rir_object *rir_global_addorget_string(struct rir *rir, const struct RFstring *s); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/ir/rir_process.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_PROCESS_H 2 | #define LFR_IR_PROCESS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | struct ast_node; 14 | struct rir_ctx; 15 | 16 | bool rir_process_ast_node(const struct ast_node *n, 17 | struct rir_ctx *ctx); 18 | 19 | /** 20 | * Process an ast node and return the generated rir object 21 | */ 22 | i_INLINE_DECL struct rir_object *rir_process_ast_node_getobj( 23 | const struct ast_node *n, 24 | struct rir_ctx *ctx) 25 | { 26 | if (!rir_process_ast_node(n, ctx)) { 27 | return NULL; 28 | } 29 | return ctx->returned_obj; 30 | } 31 | 32 | /** 33 | * Process an ast node and return its rir value 34 | */ 35 | i_INLINE_DECL struct rir_value *rir_process_ast_node_getval( 36 | const struct ast_node *n, 37 | struct rir_ctx *ctx) 38 | { 39 | struct rir_object *obj = rir_process_ast_node_getobj(n, ctx); 40 | return obj ? rir_object_value(obj) : NULL; 41 | } 42 | 43 | /** 44 | * Process an ast node and get the value of the given expression. May perform read. 45 | * Uses @ref rir_getread_val() 46 | */ 47 | i_INLINE_DECL const struct rir_value *rir_process_ast_node_getreadval( 48 | const struct ast_node *n, 49 | struct rir_ctx *ctx) 50 | { 51 | struct rir_object *obj = rir_process_ast_node_getobj(n, ctx); 52 | RF_ASSERT(obj && 53 | (obj->category == RIR_OBJ_GLOBAL || 54 | obj->category == RIR_OBJ_EXPRESSION || 55 | obj->category == RIR_OBJ_VARIABLE), 56 | "At this point either a rir global or a rir expression" 57 | "object should have been generated" 58 | ); 59 | return obj->category == RIR_OBJ_EXPRESSION 60 | ? rirctx_getread_exprval(&obj->expr, ctx) 61 | : rir_object_value(obj); 62 | } 63 | 64 | bool rir_process_ifexpr(const struct ast_node *n, struct rir_ctx *ctx); 65 | bool rir_process_forexpr(const struct ast_node *n, struct rir_ctx *ctx); 66 | bool rir_process_matchexpr(struct ast_node *n, struct rir_ctx *ctx); 67 | bool rir_match_st_populate_allocas( 68 | const struct ast_node *mcase, 69 | struct rir_object *matched_rir_obj, 70 | struct rir_ctx *ctx); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/ir/rir_typedef.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_TYPEDEF_H 2 | #define LFR_IR_RIR_TYPEDEF_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct rir_ctx; 9 | struct rir_fndef; 10 | struct type; 11 | 12 | struct rir_typedef { 13 | struct RFstring name; 14 | bool is_union; 15 | struct rir_type_arr argument_types; 16 | //! Control to be entered into the rir typedefs list 17 | struct RFilist_node ln; 18 | }; 19 | 20 | struct rir_typedef *rir_typedef_create_from_type(struct type *t, struct rir_ctx *ctx); 21 | 22 | struct rir_object *rir_typedef_create_obj( 23 | struct rir *r, 24 | struct rir_fndef *curr_fn, 25 | const struct RFstring *name, 26 | bool is_union, 27 | const struct rir_type_arr *args 28 | ); 29 | struct rir_typedef *rir_typedef_create( 30 | struct rir *r, 31 | struct rir_fndef *curr_fn, 32 | const struct RFstring *name, 33 | bool is_union, 34 | const struct rir_type_arr *args 35 | ); 36 | 37 | void rir_typedef_deinit(struct rir_typedef *t); 38 | 39 | bool rir_typedef_tostring(struct rirtostr_ctx *ctx, struct rir_typedef *t); 40 | bool rir_typedef_equal(const struct rir_typedef *t1, const struct rir_typedef *t2); 41 | const struct rir_type *rir_typedef_typeat(const struct rir_typedef *t, unsigned int i); 42 | 43 | size_t rir_typedef_bytesize(const struct rir_typedef *t); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/ir/rir_unaryop.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_UNARYOP_H 2 | #define LFR_IR_RIR_UNARYOP_H 3 | 4 | #include 5 | 6 | struct rir_ctx; 7 | struct ast_unaryop; 8 | 9 | bool rir_process_unaryop(const struct ast_unaryop *n, 10 | struct rir_ctx *ctx); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/ir/rir_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_UTILS_H 2 | #define LFR_IR_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | enum rir_code_loc { 8 | RIR_LOC_FIXEDARR, 9 | RIR_LOC_CONVERSION, 10 | RIR_LOC_FNDECL_ARGUMENTS, 11 | RIR_LOC_FNDECL_RETURN, 12 | RIR_LOC_TYPEDESC, 13 | RIR_LOC_FNCALL_MAYBE_CONVERT, 14 | RIR_LOC_FNCALL_SUM_CALL, 15 | RIR_LOC_SYMBOL_TABLE_ALLOCA, 16 | }; 17 | 18 | extern struct rir_value g_rir_const_1; 19 | extern struct rir_value g_rir_const_m1; 20 | extern struct rir_type g_rir_i32_type; 21 | 22 | /** 23 | * Initialize all the utils needed by all rir functions 24 | */ 25 | bool rir_utils_create(); 26 | void rir_utils_destroy(); 27 | 28 | /** 29 | * Get the given value or perform a read if it's a pointer 30 | */ 31 | struct rir_value *rirctx_getread_val(struct rir_value *v, struct rir_ctx *ctx); 32 | /** 33 | * Get the value of the given expression. Performs a read if necessary 34 | */ 35 | struct rir_value *rirctx_getread_exprval(struct rir_expression *e, struct rir_ctx *ctx); 36 | /** 37 | * Acts like @ref rir_getread_val() but returns the expression itself and not the value 38 | */ 39 | struct rir_expression *rirctx_getread_expr(struct rir_expression *e, struct rir_ctx *ctx); 40 | /** 41 | * Acts like @ref rir_getread_val() but returns the rir object containing the expression 42 | */ 43 | struct rir_object *rirctx_getread_obj(struct rir_object *e, struct rir_ctx *ctx); 44 | 45 | 46 | /** 47 | * Allocates a rir object, writes to it and adds both operations to 48 | * the current block 49 | * 50 | * @param t The rir type of which to allocate an object 51 | * @param value_to_write The rir value to write to the allocated object 52 | * @param ctx The rir context 53 | * @return The rir_object that was created for the allocation 54 | * or NULL in failure. 55 | */ 56 | struct rir_object *rirctx_alloc_write_add( 57 | struct rir_type *t, 58 | struct rir_value *value_to_write, 59 | struct rir_ctx *ctx 60 | ); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/ir/rir_variable.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_IR_RIR_VARIABLE_H 2 | #define LFR_IR_RIR_VARIABLE_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | struct rirtostr_ctx; 9 | struct rir_type; 10 | 11 | struct rir_variable { 12 | //! The value of the variable 13 | struct rir_value val; 14 | }; 15 | 16 | struct rir_object *rir_variable_create( 17 | struct rir_type *type, 18 | enum rir_pos pos, 19 | rir_data data 20 | ); 21 | void rir_variable_deinit(struct rir_variable *var); 22 | 23 | i_INLINE_DECL struct rir_type *rir_variable_type(struct rir_variable *v) 24 | { 25 | return v->val.type; 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /include/ownership/ownership.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_ONWERSHIP_H 2 | #define LFR_ONWERSHIP_H 3 | 4 | #include 5 | 6 | struct compiler; 7 | struct RFstring; 8 | 9 | bool ownership_pass(struct compiler *c); 10 | const struct RFstring *ow_curr_fnname(); 11 | void ow_reset_expr_idx(); 12 | unsigned int ow_expr_idx_inc(); 13 | unsigned int ow_expr_idx(); 14 | #endif 15 | -------------------------------------------------------------------------------- /include/parser/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_H 2 | #define LFR_PARSER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct info_ctx; 10 | struct lexer; 11 | struct inpfile; 12 | struct front_ctx; 13 | 14 | struct ast_parser { 15 | //! The parser common data. Should always be first. Some behaviour relies on that. 16 | struct parser_common cmn; 17 | struct ast_node *root; 18 | bool have_syntax_err; 19 | }; 20 | 21 | i_INLINE_DECL struct ast_parser *parser_common_to_astparser(const struct parser_common* c) 22 | { 23 | RF_ASSERT(c->type == PARSER_AST, "Expected AST parser"); 24 | return container_of(c, struct ast_parser, cmn); 25 | } 26 | 27 | 28 | bool ast_parser_init( 29 | struct ast_parser *p, 30 | struct inpfile *f, 31 | struct lexer *lex, 32 | struct info_ctx *info, 33 | struct front_ctx *front 34 | ); 35 | struct ast_parser *ast_parser_create( 36 | struct inpfile *f, 37 | struct lexer *lex, 38 | struct info_ctx *info, 39 | struct front_ctx *front 40 | ); 41 | void ast_parser_deinit(struct ast_parser *p); 42 | void ast_parser_destroy(struct ast_parser *p); 43 | 44 | 45 | /** 46 | * Performs the scanning and parsing stage on a file 47 | */ 48 | bool ast_parser_parse_file(struct ast_parser *p); 49 | /** 50 | * Mark all children of node @a n as finalized after parsing and 51 | * checks for a main function to see if this should be the main module 52 | */ 53 | bool ast_parser_finalize_parsing(struct ast_parser *p); 54 | /** 55 | * Pre-analysis stage for a file. Scanning, parsing and finalization 56 | * This is the main function for parsing. 57 | */ 58 | bool ast_parser_process_file(struct ast_parser *p); 59 | 60 | 61 | 62 | i_INLINE_DECL void ast_parser_set_syntax_error(struct ast_parser *parser) 63 | { 64 | parser->have_syntax_err = true; 65 | } 66 | 67 | i_INLINE_DECL bool ast_parser_has_syntax_error(struct ast_parser *parser) 68 | { 69 | return parser->have_syntax_err; 70 | } 71 | 72 | i_INLINE_DECL bool ast_parser_has_syntax_error_reset(struct ast_parser *parser) 73 | { 74 | bool ret = parser->have_syntax_err; 75 | parser->have_syntax_err = false; 76 | return ret; 77 | } 78 | 79 | /** 80 | * Acts just like info_ctx_rollback() except it also resets the has_syntax_error 81 | * variable. 82 | * 83 | * TODO: Make this smarter, get rid of the has_syntax_error logic and just use the 84 | * rollback mechanism if possible 85 | */ 86 | void ast_parser_info_rollback(struct ast_parser *parser); 87 | 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /include/parser/parser_common.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_COMMON_H 2 | #define LFR_PARSER_COMMON_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct inpfile; 10 | struct lexer; 11 | struct info_ctx; 12 | 13 | enum parser_type { 14 | PARSER_AST, 15 | PARSER_RIR 16 | }; 17 | 18 | struct parser_common { 19 | //! The type of the parser 20 | enum parser_type type; 21 | //! The input file representation 22 | struct inpfile *file; 23 | //! The lexer part of the parser 24 | struct lexer *lexer; 25 | //! Pointer to the common info context 26 | struct info_ctx *info; 27 | //! A pointer to the front_ctx that owns the parser. 28 | struct front_ctx *front; 29 | }; 30 | 31 | i_INLINE_DECL void parser_common_init( 32 | struct parser_common *c, 33 | enum parser_type type, 34 | struct front_ctx *front, 35 | struct inpfile *f, 36 | struct lexer *lexer, 37 | struct info_ctx *info 38 | ) 39 | { 40 | c->type = type; 41 | c->front = front; 42 | c->file = f; 43 | c->lexer = lexer; 44 | c->info = info; 45 | } 46 | 47 | i_INLINE_DECL void parser_common_deinit(struct parser_common *c) 48 | { 49 | c->lexer = NULL; 50 | c->file = NULL; 51 | c->info = NULL; 52 | c->front = NULL; 53 | } 54 | 55 | /** 56 | * Destroy a parser from its common data 57 | * 58 | * @note: This will call the appropriate destruction function and also destroy 59 | * the parser pointer that contains the common data 60 | */ 61 | void parser_destroy(struct parser_common *c); 62 | 63 | bool parser_parse(struct parser_common *c); 64 | 65 | 66 | /** 67 | * Get the lexer associated with this parser 68 | */ 69 | #define parser_lexer(i_pptr_) ((i_pptr_)->cmn.lexer) 70 | 71 | /** 72 | * Get the front context associated with this parser 73 | */ 74 | #define parser_front(i_pptr_) ((i_pptr_)->cmn.front) 75 | 76 | 77 | struct ast_node *parser_ast_get_root(struct parser_common *c); 78 | struct ast_node *parser_ast_move_root(struct parser_common *c); 79 | struct rir *parser_rir(struct parser_common *c); 80 | 81 | /* 82 | * The following macros are dangerous and need typechecking before use. 83 | * The type of the argument must be either ast_parser or rir_parser. Anything 84 | * else will lead to ugly undefined behaviour 85 | */ 86 | 87 | /** 88 | * Get the parser's common data from any parser. 89 | */ 90 | #define parser_to_common(i_pptr_) ((struct parser_common*)i_pptr_) 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /include/serializer/serializer.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_SERIALIZER_H 2 | #define LFR_SERIALIZER_H 3 | 4 | #include 5 | #include 6 | 7 | enum serializer_rc { 8 | SERC_SUCCESS_CONTINUE = 0, 9 | SERC_SUCCESS_EXIT, 10 | SERC_FAILURE, 11 | 12 | }; 13 | 14 | struct ast_node; 15 | struct analyzer; 16 | struct inpfile; 17 | struct module; 18 | 19 | /** 20 | * The serializer deals with data exporting and serialization (if needed) 21 | *after the end of a succesful analysis. 22 | */ 23 | struct serializer { 24 | //! A non-owned pointer to the AST 25 | struct ast_node *root; 26 | //! A non-owned pointer to object holding the compiler arguments 27 | struct compiler_args *args; 28 | }; 29 | 30 | 31 | struct serializer *serializer_create(struct compiler_args *args); 32 | 33 | bool serializer_init(struct serializer *sr, struct compiler_args *args); 34 | 35 | void serializer_destroy(struct serializer *sr); 36 | 37 | bool serializer_process(struct serializer *sr, 38 | const struct module *mod); 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/types/type_decls.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPES_DECL_H 2 | #define LFR_TYPES_DECL_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include // for binary operations enum 11 | 12 | struct rir_type; 13 | struct type; 14 | 15 | //! An array of types 16 | struct arr_types {darray(struct type*);}; 17 | 18 | // NOTE: preserve order, some functions depend on it 19 | // order should be same as rir elementary types 20 | enum elementary_type { 21 | ELEMENTARY_TYPE_INT_8 = 0, 22 | ELEMENTARY_TYPE_UINT_8, 23 | ELEMENTARY_TYPE_INT_16, 24 | ELEMENTARY_TYPE_UINT_16, 25 | ELEMENTARY_TYPE_INT_32, 26 | ELEMENTARY_TYPE_UINT_32, 27 | ELEMENTARY_TYPE_INT_64, 28 | ELEMENTARY_TYPE_UINT_64, 29 | ELEMENTARY_TYPE_INT, 30 | ELEMENTARY_TYPE_UINT, 31 | ELEMENTARY_TYPE_FLOAT_32, 32 | ELEMENTARY_TYPE_FLOAT_64, 33 | ELEMENTARY_TYPE_STRING, 34 | ELEMENTARY_TYPE_BOOL, 35 | ELEMENTARY_TYPE_NIL, 36 | 37 | ELEMENTARY_TYPE_TYPES_COUNT /* keep as last */ 38 | }; 39 | 40 | enum typeop_type { 41 | TYPEOP_INVALID, 42 | TYPEOP_SUM, 43 | TYPEOP_PRODUCT, 44 | TYPEOP_IMPLICATION 45 | }; 46 | 47 | enum type_category { 48 | TYPE_CATEGORY_OPERATOR = 0, /* a type combination of other types */ 49 | TYPE_CATEGORY_ELEMENTARY, /* an elementary/builtin type */ 50 | TYPE_CATEGORY_DEFINED, /* a user defined type */ 51 | TYPE_CATEGORY_WILDCARD, /* the type of '_' */ 52 | TYPE_CATEGORY_GENERIC, /* a generic type as declared by the user */ 53 | TYPE_CATEGORY_MODULE, /* type of a module */ 54 | TYPE_CATEGORY_ARRAY /* type of an array */ 55 | }; 56 | 57 | struct type_elementary { 58 | //! What kind of elementary type this is 59 | enum elementary_type etype; 60 | }; 61 | 62 | struct type_operator { 63 | enum typeop_type type; 64 | //! Types that consitute this type 65 | struct arr_types operands; 66 | }; 67 | 68 | struct type_defined { 69 | const struct RFstring *name; 70 | struct type *type; 71 | }; 72 | 73 | struct type_foreignfn { 74 | const struct RFstring *name; 75 | }; 76 | 77 | struct type_module { 78 | const struct RFstring *name; 79 | }; 80 | 81 | struct arr_int64 { darray(int64_t);}; 82 | struct type_array { 83 | struct arr_int64 dimensions; 84 | const struct type *member_type; 85 | }; 86 | 87 | struct type { 88 | enum type_category category; 89 | bool is_constant; 90 | union { 91 | struct type_defined defined; 92 | struct type_operator operator; 93 | struct type_elementary elementary; 94 | struct type_foreignfn foreignfn; 95 | struct type_module module; 96 | struct type_array array; 97 | }; 98 | }; 99 | #endif 100 | -------------------------------------------------------------------------------- /include/types/type_function.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPES_FUNCTION_H 2 | #define LFR_TYPES_FUNCTION_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | struct analyzer; 11 | struct module; 12 | 13 | i_INLINE_DECL bool type_is_function(const struct type *t) 14 | { 15 | return (t->category == TYPE_CATEGORY_OPERATOR && 16 | t->operator.type == TYPEOP_IMPLICATION); 17 | } 18 | 19 | /** 20 | * Returns true if the type can be called. 21 | * 22 | * Callable types are functions, custom user defined types since 23 | * they can have a constructor and almost all elementary types for 24 | * explicit conversion 25 | */ 26 | i_INLINE_DECL bool type_is_callable(const struct type *t) 27 | { 28 | return type_is_function(t) || 29 | t->category == TYPE_CATEGORY_DEFINED || 30 | type_is_explicitly_convertable_elementary(t); 31 | } 32 | 33 | struct type *type_function_get_argtype(const struct type *t); 34 | struct type *type_function_get_rettype(const struct type *t); 35 | 36 | //! Gets the type description of the arguments of a callable type 37 | i_INLINE_DECL const struct type *type_callable_get_argtype(const struct type *t) 38 | { 39 | RF_ASSERT(type_is_callable(t) && !type_is_explicitly_convertable_elementary(t), 40 | "Function should be called for callable types and not conversions"); 41 | if (type_is_function(t)) { 42 | return type_function_get_argtype(t); 43 | } 44 | // else it's a constructor of a defined type 45 | return t; 46 | } 47 | 48 | i_INLINE_DECL struct type *type_callable_get_rettype(const struct type *t) 49 | { 50 | RF_ASSERT(type_is_callable(t), "Non callable type detected"); 51 | if (type_is_function(t)) { 52 | return type_function_get_rettype(t); 53 | } 54 | // else it's either a constructor of a defined type or explicit conversion, 55 | // so returned type is actually t 56 | return (struct type*)t; 57 | } 58 | 59 | /** 60 | * Provided a callable type will return a pointer to a string of either 61 | * "function" or "constructor" 62 | */ 63 | const struct RFstring *type_callable_category_str(const struct type *t); 64 | 65 | /** 66 | * Initialize a type structure as a function type 67 | */ 68 | void type_function_init( 69 | struct type *t, 70 | struct type *arg_type, 71 | struct type *ret_type 72 | ); 73 | struct type *type_function_create( 74 | struct module *m, 75 | struct type *arg_type, 76 | struct type *ret_type 77 | ); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /include/types/type_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TYPES_TYPE_UTILS_H 2 | #define LFR_TYPES_TYPE_UTILS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | i_INLINE_DECL bool ast_node_is_elementary_identifier(struct ast_node *n) 10 | { 11 | return n->type == AST_IDENTIFIER && type_is_simple_elementary(n->expression_type); 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/utils/common.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_UTILS_COMMON_H 2 | #define LFR_UTILS_COMMON_H 3 | 4 | /** 5 | * Denotes which code path we are following as far as rir is concerned. 6 | * 7 | * + RIRPOS_AST: 8 | * + RIRPOS_PARSE: Then the RIR is created by directly parsing the RIR source. 9 | */ 10 | enum rir_pos { 11 | //! Code path when the RIR is created normally by parsing the source file, 12 | //! generating the AST and then analyzing it to create the RIR. 13 | RIRPOS_AST = 1, 14 | //! Code path where RIR is created by directly parsing the RIR source. 15 | RIRPOS_PARSE = 2, 16 | //! Given when we don't want to specify code path, or we got illegal path. 17 | RIRPOS_NONE = 3, 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/utils/common_strings.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_UTILS_COMMON_STRINGS_H 2 | #define LFR_UTILS_COMMON_STRINGS_H 3 | 4 | #include 5 | 6 | extern const struct RFstring g_str_true; 7 | extern const struct RFstring g_str_false; 8 | extern const struct RFstring g_str_main; 9 | extern const struct RFstring g_str_stdlib; 10 | extern const struct RFstring g_str_fnstart; 11 | extern const struct RFstring g_str_string; 12 | extern const struct RFstring g_str_defined; 13 | extern const struct RFstring g_str_foreign; 14 | extern const struct RFstring g_str_elementary; 15 | extern const struct RFstring g_str_composite; 16 | extern const struct RFstring g_str_array; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/utils/data.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_UTILS_DATA_H 2 | #define LFR_UTILS_DATA_H 3 | 4 | #include 5 | 6 | /** 7 | * Returns the name of the location where the compiler can save data in the system 8 | * 9 | * @TODO Make this customizable 10 | */ 11 | const struct RFstring *rf_data_dir(); 12 | 13 | /** 14 | * Ensure the data directory exists and if it does not already then create it 15 | */ 16 | bool rf_data_dir_exists(); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/utils/string_set.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_STRING_SET_H 2 | #define LFR_STRING_SET_H 3 | 4 | #include 5 | #include 6 | 7 | struct RFstring; 8 | 9 | i_INLINE_DECL const void *string_objset_key(const struct RFstring *s) 10 | { 11 | return (const void*)s; 12 | } 13 | 14 | size_t string_objset_hashfn(const struct RFstring *s); 15 | bool string_objset_eqfn(const struct RFstring *s1, 16 | const struct RFstring *s2); 17 | 18 | OBJSET_DEFINE_TYPE(string, 19 | struct RFstring, 20 | string_objset_key, 21 | string_objset_hashfn, 22 | string_objset_eqfn); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/utils/traversal.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_UTILS_TRAVERSAL_H 2 | #define LFR_UTILS_TRAVERSAL_H 3 | 4 | #include 5 | #include 6 | 7 | enum traversal_cb_res { 8 | //! Error occured in the callback 9 | TRAVERSAL_CB_ERROR = -2, 10 | //! Error occured in the callback, will stop traversal 11 | TRAVERSAL_CB_FATAL_ERROR = -1, 12 | //! Callback was succesfull 13 | TRAVERSAL_CB_OK = 0, 14 | //! Callback was succesfull and also stop iteration 15 | TRAVERSAL_CB_OK_AND_STOP = 1, 16 | }; 17 | 18 | i_INLINE_DECL bool traversal_success(enum traversal_cb_res rc) 19 | { 20 | return rc == TRAVERSAL_CB_OK || rc == TRAVERSAL_CB_OK_AND_STOP; 21 | } 22 | 23 | i_INLINE_DECL bool traversal_stop(enum traversal_cb_res rc) 24 | { 25 | return rc == TRAVERSAL_CB_OK_AND_STOP || rc == TRAVERSAL_CB_FATAL_ERROR; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(argtable) 2 | -------------------------------------------------------------------------------- /lib/argtable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/argtable3.c") 2 | -------------------------------------------------------------------------------- /lib/argtable/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of STEWART HEITMANN nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 20 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | -------------------------------------------------------------------------------- /lib/argtable/examples/testargtable3.c: -------------------------------------------------------------------------------- 1 | #include "argtable3.h" 2 | 3 | /* global arg_xxx structs */ 4 | struct arg_lit *a, *b, *c, *verb, *help, *version; 5 | struct arg_int *scal; 6 | struct arg_file *o, *file; 7 | struct arg_end *end; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | /* the global arg_xxx structs are initialised within the argtable */ 12 | void *argtable[] = { 13 | help = arg_lit0(NULL, "help", "display this help and exit"), 14 | version = arg_lit0(NULL, "version", "display version info and exit"), 15 | a = arg_lit0("a", NULL,"the -a option"), 16 | b = arg_lit0("b", NULL, "the -b option"), 17 | c = arg_lit0("c", NULL, "the -c option"), 18 | scal = arg_int0(NULL, "scalar", "", "foo value"), 19 | verb = arg_lit0("v", "verbose", "verbose output"), 20 | o = arg_file0("o", NULL, "myfile", "output file"), 21 | file = arg_filen(NULL, NULL, "", 1, 100, "input files"), 22 | end = arg_end(20), 23 | }; 24 | 25 | int exitcode = 0; 26 | char progname[] = "testargtable2.exe"; 27 | 28 | int nerrors; 29 | nerrors = arg_parse(argc,argv,argtable); 30 | 31 | /* special case: '--help' takes precedence over error reporting */ 32 | if (help->count > 0) 33 | { 34 | printf("Usage: %s", progname); 35 | arg_print_syntax(stdout, argtable, "\n"); 36 | printf("List information about the FILE(s) " 37 | "(the current directory by default).\n\n"); 38 | arg_print_glossary(stdout, argtable, " %-25s %s\n"); 39 | exitcode = 0; 40 | goto exit; 41 | } 42 | 43 | /* If the parser returned any errors then display them and exit */ 44 | if (nerrors > 0) 45 | { 46 | /* Display the error details contained in the arg_end struct.*/ 47 | arg_print_errors(stdout, end, progname); 48 | printf("Try '%s --help' for more information.\n", progname); 49 | exitcode = 1; 50 | goto exit; 51 | } 52 | 53 | exit: 54 | /* deallocate each non-null entry in argtable[] */ 55 | arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); 56 | return exitcode; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /lib/argtable/tests/testall.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "CuTest.h" 4 | 5 | CuSuite* get_arglit_testsuite(); 6 | CuSuite* get_argstr_testsuite(); 7 | CuSuite* get_argint_testsuite(); 8 | CuSuite* get_argdate_testsuite(); 9 | CuSuite* get_argdbl_testsuite(); 10 | CuSuite* get_argfile_testsuite(); 11 | CuSuite* get_argrex_testsuite(); 12 | 13 | void RunAllTests(void) 14 | { 15 | CuString *output = CuStringNew(); 16 | CuSuite* suite = CuSuiteNew(); 17 | 18 | CuSuiteAddSuite(suite, get_arglit_testsuite()); 19 | CuSuiteAddSuite(suite, get_argstr_testsuite()); 20 | CuSuiteAddSuite(suite, get_argint_testsuite()); 21 | CuSuiteAddSuite(suite, get_argdate_testsuite()); 22 | CuSuiteAddSuite(suite, get_argdbl_testsuite()); 23 | CuSuiteAddSuite(suite, get_argfile_testsuite()); 24 | CuSuiteAddSuite(suite, get_argrex_testsuite()); 25 | 26 | CuSuiteRun(suite); 27 | CuSuiteSummary(suite, output); 28 | CuSuiteDetails(suite, output); 29 | printf("%s\n", output->buffer); 30 | } 31 | 32 | int main(void) 33 | { 34 | RunAllTests(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(analyzer) 2 | add_subdirectory(ast) 3 | add_subdirectory(backend) 4 | add_subdirectory(info) 5 | add_subdirectory(ir) 6 | add_subdirectory(lexer) 7 | add_subdirectory(ownership) 8 | add_subdirectory(parser) 9 | add_subdirectory(serializer) 10 | add_subdirectory(types) 11 | add_subdirectory(utils) 12 | 13 | include(RFTargetSources) 14 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/compiler.c" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/compiler_args.c" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/front_ctx.c" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/inpfile.c" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/inplocation.c" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/inpoffset.c" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/inpstr.c" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/module.c") 22 | target_sources(refu PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/main.c") 23 | -------------------------------------------------------------------------------- /src/analyzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/analyzer.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/analyzer_pass1.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/symbol_table.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/type_set.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/typecheck.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/typecheck_arr.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/typecheck_functions.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/typecheck_forexpr.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/typecheck_matchexpr.c") 10 | -------------------------------------------------------------------------------- /src/analyzer/analyzer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | i_INLINE_INS void analyzer_traversal_ctx_init(struct analyzer_traversal_ctx *ctx, 13 | struct module *m); 14 | i_INLINE_INS void analyzer_traversal_ctx_deinit(struct analyzer_traversal_ctx *ctx); 15 | i_INLINE_INS struct ast_node *analyzer_traversal_ctx_get_nth_parent( 16 | unsigned int num, 17 | struct analyzer_traversal_ctx *ctx); 18 | i_INLINE_INS struct ast_node *analyzer_traversal_ctx_get_nth_parent_or_die( 19 | unsigned int num, 20 | struct analyzer_traversal_ctx *ctx); 21 | 22 | bool analyzer_traversal_ctx_traverse_parents(struct analyzer_traversal_ctx *ctx, 23 | analyzer_traversal_parents_cb cb, 24 | void *user_arg) 25 | { 26 | int index = darray_size(ctx->parent_nodes) - 2; 27 | while (index >= 0) { 28 | if (cb(darray_item(ctx->parent_nodes, index), user_arg)) { 29 | return true; 30 | } 31 | --index; 32 | } 33 | return false; 34 | } 35 | 36 | static void analyzer_finalize_fndecl(struct ast_node *n) 37 | { 38 | // figure out the number of arguments 39 | struct ast_node *fn_args = ast_fndecl_args_get(n); 40 | if (fn_args) { 41 | const struct type *t = ast_node_get_type(ast_fndecl_args_get(n)); 42 | n->fndecl.args_num = (darray_size(t->operator.operands) == 0) 43 | ? 1 44 | : darray_size(t->operator.operands); 45 | } else { 46 | n->fndecl.args_num = 0; 47 | } 48 | } 49 | 50 | static enum traversal_cb_res analyzer_finalize_do(struct ast_node *n, void *user_arg) 51 | { 52 | struct module *m = user_arg; 53 | (void)m; 54 | switch (n->type) { 55 | case AST_FUNCTION_DECLARATION: 56 | analyzer_finalize_fndecl(n); 57 | break; 58 | default: 59 | break; 60 | } 61 | // finally set the state 62 | n->state = AST_NODE_STATE_RIR_END; 63 | return TRAVERSAL_CB_OK; 64 | } 65 | 66 | static bool do_nothing(struct ast_node *n, void *user_arg) { return true; } 67 | 68 | bool analyzer_finalize(struct module *m) 69 | { 70 | m->rir = rir_create(); 71 | // TODO: if we don't have any actual pre_callback then use ast_post_traverse_tree() 72 | bool ret = (TRAVERSAL_CB_OK == ast_traverse_tree_nostop_post_cb( 73 | m->node, 74 | do_nothing, 75 | NULL, 76 | analyzer_finalize_do, 77 | m 78 | ) 79 | ); 80 | return ret; 81 | } 82 | -------------------------------------------------------------------------------- /src/ast/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/arr.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/ast.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/ast_type_traversal.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/ast_utils.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/block.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/constants.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/function.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/generics.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/identifier.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/ifexpr.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/forexpr.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/iterable.c" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/matchexpr.c" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/module.c" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/operators.c" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/returnstmt.c" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/string_literal.c" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/type.c" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/typeclass.c" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/vardecl.c") 21 | -------------------------------------------------------------------------------- /src/ast/arr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct ast_node *ast_arrspec_create( 5 | const struct inplocation_mark *start, 6 | const struct inplocation_mark *end, 7 | struct arr_ast_nodes *dimensions 8 | ) 9 | { 10 | struct ast_node *ret; 11 | ret = ast_node_create_marks(AST_ARRAY_SPEC, start, end); 12 | if (!ret) { 13 | RF_ERRNOMEM(); 14 | return NULL; 15 | } 16 | 17 | ast_node_copy_children(ret, dimensions); 18 | return ret; 19 | } 20 | 21 | i_INLINE_INS unsigned int ast_arrspec_dimensions_num(struct ast_node *n); 22 | 23 | 24 | struct ast_node *ast_bracketlist_create( 25 | const struct inplocation_mark *start, 26 | const struct inplocation_mark *end, 27 | struct ast_node *args) 28 | { 29 | struct ast_node *ret; 30 | ret = ast_node_create_marks(AST_BRACKET_LIST, start, end); 31 | if (!ret) { 32 | RF_ERRNOMEM(); 33 | return NULL; 34 | } 35 | 36 | if (args) { 37 | ast_node_add_child(ret, args); 38 | } 39 | return ret; 40 | } 41 | 42 | static bool populate_bracketlist_cb(struct ast_node *n, struct arr_ast_nodes *members) 43 | { 44 | darray_push(*members, n); 45 | return true; 46 | } 47 | 48 | struct arr_ast_nodes *ast_bracketlist_members(struct ast_node *n) 49 | { 50 | AST_NODE_ASSERT_TYPE(n, AST_BRACKET_LIST); 51 | if (n->state <= AST_NODE_STATE_ANALYZER_PASS1) { 52 | darray_init(n->bracketlist.members); 53 | ast_bracketlist_foreach_member( 54 | n, 55 | (exprlist_cb)populate_bracketlist_cb, 56 | &n->bracketlist.members 57 | ); 58 | n->state = AST_NODE_STATE_TYPECHECK_1; 59 | } 60 | return &n->bracketlist.members; 61 | } 62 | 63 | i_INLINE_INS bool ast_bracketlist_foreach_member( 64 | const struct ast_node *n, 65 | exprlist_cb cb, 66 | void *user 67 | ); 68 | -------------------------------------------------------------------------------- /src/ast/block.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | struct ast_node *ast_block_create() 6 | { 7 | struct ast_node *ret; 8 | ret = ast_node_create(AST_BLOCK); 9 | if (!ret) { 10 | RF_ERRNOMEM(); 11 | return NULL; 12 | } 13 | 14 | return ret; 15 | } 16 | 17 | i_INLINE_INS bool ast_block_symbol_table_init(struct ast_node *n, 18 | struct module *m); 19 | i_INLINE_INS struct symbol_table* ast_block_symbol_table_get(struct ast_node *n); 20 | i_INLINE_INS void ast_block_add_element(struct ast_node *n, struct ast_node *element); 21 | -------------------------------------------------------------------------------- /src/ast/forexpr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct ast_node *ast_forexpr_create( 5 | const struct inplocation_mark *start, 6 | const struct inplocation_mark *end, 7 | struct ast_node *loopvar, 8 | struct ast_node *iterable, 9 | struct ast_node *body) 10 | { 11 | struct ast_node *ret; 12 | ret = ast_node_create_marks(AST_FOR_EXPRESSION, start, end); 13 | if (!ret) { 14 | return NULL; 15 | } 16 | 17 | ast_node_register_child(ret, loopvar, forexpr.loopvar); 18 | ast_node_register_child(ret, iterable, forexpr.iterable); 19 | ast_node_register_child(ret, body, forexpr.body); 20 | 21 | return ret; 22 | } 23 | 24 | i_INLINE_INS struct symbol_table* ast_forexpr_symbol_table_get(struct ast_node *n); 25 | i_INLINE_INS bool ast_forexpr_symbol_table_init(struct ast_node *n, struct module *m); 26 | i_INLINE_INS struct ast_node* ast_forexpr_iterable_get(const struct ast_node *n); 27 | i_INLINE_INS struct ast_node* ast_forexpr_loopvar_get(const struct ast_node *n); 28 | i_INLINE_INS struct ast_node* ast_forexpr_body_get(const struct ast_node *n); 29 | -------------------------------------------------------------------------------- /src/ast/generics.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct ast_node *ast_genrtype_create(struct ast_node *type, struct ast_node *id) 10 | { 11 | struct ast_node *ret; 12 | 13 | ret = ast_node_create_marks(AST_GENERIC_TYPE, ast_node_startmark(type), 14 | ast_node_endmark(id)); 15 | if (!ret) { 16 | RF_ERRNOMEM(); 17 | return NULL; 18 | } 19 | 20 | ast_node_add_child(ret, type); 21 | ret->genrtype.type = type; 22 | ast_node_add_child(ret, id); 23 | ret->genrtype.id = id; 24 | return ret; 25 | } 26 | 27 | i_INLINE_INS const struct RFstring *ast_genrtype_id_str(struct ast_node *n); 28 | 29 | struct ast_node *ast_genrdecl_create(const struct inplocation_mark *start, 30 | const struct inplocation_mark *end) 31 | { 32 | struct ast_node *ret; 33 | 34 | ret = ast_node_create_marks(AST_GENERIC_DECLARATION, start, end); 35 | if (!ret) { 36 | RF_ERRNOMEM(); 37 | return NULL; 38 | } 39 | return ret; 40 | } 41 | 42 | struct ast_node *ast_genrdecl_string_is_genr(struct ast_node *n, 43 | const struct RFstring *id) 44 | { 45 | 46 | AST_NODE_ASSERT_TYPE(n, AST_GENERIC_DECLARATION); 47 | struct ast_node **child; 48 | darray_foreach(child, n->children) { 49 | if (rf_string_equal(id, ast_genrtype_id_str(*child))) { 50 | return *child; 51 | } 52 | } 53 | return NULL; 54 | } 55 | 56 | struct ast_node *ast_genrattr_create(const struct inplocation_mark *start, 57 | const struct inplocation_mark *end) 58 | { 59 | struct ast_node *ret; 60 | 61 | ret = ast_node_create_marks(AST_GENERIC_ATTRIBUTE, start, end); 62 | if (!ret) { 63 | RF_ERRNOMEM(); 64 | return NULL; 65 | } 66 | return ret; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/ast/ifexpr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct ast_node *ast_condbranch_create(const struct inplocation_mark *start, 5 | const struct inplocation_mark *end, 6 | struct ast_node *cond, 7 | struct ast_node *body) 8 | { 9 | struct ast_node *ret; 10 | ret = ast_node_create_marks(AST_CONDITIONAL_BRANCH, start, end); 11 | if (!ret) { 12 | return NULL; 13 | } 14 | 15 | ast_node_register_child(ret, cond, condbranch.cond); 16 | ast_node_register_child(ret, body, condbranch.body); 17 | 18 | return ret; 19 | } 20 | 21 | i_INLINE_INS struct ast_node *ast_condbranch_condition_get(const struct ast_node *n); 22 | i_INLINE_INS struct ast_node *ast_condbranch_body_get(const struct ast_node *n); 23 | 24 | struct ast_node *ast_ifexpr_create(const struct inplocation_mark *start, 25 | const struct inplocation_mark *end, 26 | struct ast_node *taken_branch, 27 | struct ast_node *fall_through_branch) 28 | { 29 | struct ast_node *ret; 30 | ret = ast_node_create_marks(AST_IF_EXPRESSION, start, end); 31 | if (!ret) { 32 | return NULL; 33 | } 34 | 35 | ast_node_register_child(ret, taken_branch, ifexpr.taken_branch); 36 | ast_node_register_child(ret, fall_through_branch, ifexpr.fallthrough_branch); 37 | 38 | return ret; 39 | } 40 | 41 | i_INLINE_INS void ast_ifexpr_add_fallthrough_branch(struct ast_node *n, 42 | struct ast_node *branch); 43 | 44 | i_INLINE_INS struct ast_node *ast_ifexpr_condition_get(const struct ast_node *ifexpr); 45 | i_INLINE_INS struct ast_node *ast_ifexpr_taken_block_get(const struct ast_node *ifexpr); 46 | i_INLINE_INS struct ast_node *ast_ifexpr_taken_branch_get(const struct ast_node *ifexpr); 47 | i_INLINE_INS struct ast_node *ast_ifexpr_fallthrough_branch_get(const struct ast_node *ifexpr); 48 | -------------------------------------------------------------------------------- /src/ast/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | /* -- ast import functions -- */ 4 | struct ast_node *ast_import_create(const struct inplocation_mark *start, 5 | const struct inplocation_mark *end, 6 | bool foreign) 7 | { 8 | struct ast_node *ret; 9 | ret = ast_node_create_marks(AST_IMPORT, start, end); 10 | if (!ret) { 11 | return NULL; 12 | } 13 | ret->import.foreign = foreign; 14 | return ret; 15 | } 16 | 17 | i_INLINE_INS bool ast_import_is_foreign(const struct ast_node *n); 18 | i_INLINE_INS bool ast_node_is_foreign_import(const struct ast_node *n); 19 | 20 | /* -- ast module functions -- */ 21 | struct ast_node *ast_module_create(const struct inplocation_mark *start, 22 | const struct inplocation_mark *end, 23 | struct ast_node *name, 24 | struct ast_node *args) 25 | { 26 | struct ast_node *ret; 27 | ret = ast_node_create_marks(AST_MODULE, start, end); 28 | if (!ret) { 29 | return NULL; 30 | } 31 | ast_node_register_child(ret, name, module.name); 32 | ast_node_register_child(ret, args, module.args); 33 | 34 | return ret; 35 | } 36 | 37 | i_INLINE_INS struct symbol_table *ast_module_symbol_table_get(struct ast_node *n); 38 | i_INLINE_INS const struct RFstring *ast_module_name(const struct ast_node *n); 39 | -------------------------------------------------------------------------------- /src/ast/returnstmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ast_node *ast_returnstmt_create(const struct inplocation_mark *start, 4 | const struct inplocation_mark *end, 5 | struct ast_node *expr) 6 | { 7 | struct ast_node *ret; 8 | 9 | ret = ast_node_create_marks(AST_RETURN_STATEMENT, start, end); 10 | if (!ret) { 11 | RF_ERRNOMEM(); 12 | return NULL; 13 | } 14 | 15 | ast_node_register_child(ret, expr, returnstmt.expr); 16 | return ret; 17 | } 18 | 19 | i_INLINE_INS struct ast_node *ast_returnstmt_expr_get(const struct ast_node *n); 20 | -------------------------------------------------------------------------------- /src/ast/string_literal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | struct ast_node *ast_string_literal_create(struct inplocation *loc) 9 | { 10 | struct ast_node *ret; 11 | ret = ast_node_create_loc(AST_STRING_LITERAL, loc); 12 | if (!ret) { 13 | return NULL; 14 | } 15 | RF_STRING_SHALLOW_INIT( 16 | &ret->string_literal.string, 17 | loc->start.p + 1, 18 | loc->end.p - loc->start.p - 1 19 | ); 20 | ret->string_literal.hash = rf_hash_str_stable(&ret->string_literal.string, 0); 21 | 22 | return ret; 23 | } 24 | 25 | bool ast_string_literal_hash_create(struct ast_node *n, struct module *m) 26 | { 27 | return rf_objset_add(&m->string_literals_set, string, &n->string_literal.string); 28 | } 29 | 30 | i_INLINE_INS const struct RFstring *ast_string_literal_get_str(const struct ast_node *lit); 31 | i_INLINE_INS uint32_t ast_string_literal_get_hash(const struct ast_node *lit); 32 | -------------------------------------------------------------------------------- /src/ast/typeclass.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | struct ast_node *ast_typeclass_create(const struct inplocation_mark *start, 6 | const struct inplocation_mark *end, 7 | struct ast_node *name, 8 | struct ast_node *genr) 9 | { 10 | struct ast_node *ret; 11 | AST_NODE_ASSERT_TYPE(name, AST_IDENTIFIER); 12 | 13 | ret = ast_node_create_marks(AST_TYPECLASS_DECLARATION, start, end); 14 | if (!ret) { 15 | RF_ERRNOMEM(); 16 | return NULL; 17 | } 18 | 19 | ast_node_register_child(ret, name, typeclass.name); 20 | ast_node_register_child(ret, genr, typeclass.generics); 21 | 22 | return ret; 23 | } 24 | 25 | struct ast_node *ast_typeinstance_create(const struct inplocation_mark *start, 26 | const struct inplocation_mark *end, 27 | struct ast_node *class_name, 28 | struct ast_node *type_name, 29 | struct ast_node *genr) 30 | { 31 | struct ast_node *ret; 32 | AST_NODE_ASSERT_TYPE(class_name, AST_IDENTIFIER); 33 | AST_NODE_ASSERT_TYPE(type_name, AST_IDENTIFIER); 34 | 35 | ret = ast_node_create_marks(AST_TYPECLASS_INSTANCE, start, end); 36 | if (!ret) { 37 | RF_ERRNOMEM(); 38 | return NULL; 39 | } 40 | 41 | ast_node_register_child(ret, class_name, typeinstance.class_name); 42 | ast_node_register_child(ret, type_name, typeinstance.type_name); 43 | ast_node_register_child(ret, genr, typeinstance.generics); 44 | 45 | return ret; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/ast/vardecl.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | struct ast_node *ast_vardecl_create(const struct inplocation_mark *start, 9 | const struct inplocation_mark *end, 10 | struct ast_node *leaf) 11 | { 12 | struct ast_node *ret; 13 | RF_ASSERT( 14 | leaf->type == AST_TYPE_LEAF, 15 | "Illegal ast node type \""RFS_PF"\"in vardecl creation", 16 | RFS_PA(leaf) 17 | ); 18 | 19 | ret = ast_node_create_marks(AST_VARIABLE_DECLARATION, start, end); 20 | if (!ret) { 21 | RF_ERRNOMEM(); 22 | return NULL; 23 | } 24 | 25 | ast_node_register_child(ret, leaf, vardecl.leaf); 26 | return ret; 27 | } 28 | 29 | i_INLINE_INS struct ast_node *ast_vardecl_desc_get(const struct ast_node *n); 30 | -------------------------------------------------------------------------------- /src/backend/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/llvm.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_arrays.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_ast.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_conversion.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_functions.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_globals.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_operators.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_types.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_utils.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/llvm_values.c") 11 | -------------------------------------------------------------------------------- /src/backend/llvm_arrays.c: -------------------------------------------------------------------------------- 1 | #include "llvm_arrays.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "llvm_ast.h" 9 | #include "llvm_utils.h" 10 | #include "llvm_values.h" 11 | 12 | #define DEFAULT_PTR_ADDRESS_SPACE 0 13 | 14 | LLVMValueRef bllvm_compile_fixedarr( 15 | const struct rir_expression *expr, 16 | struct llvm_traversal_ctx *ctx) 17 | { 18 | RF_ASSERT(expr->type == RIR_EXPRESSION_FIXEDARR, "unexpexted expression"); 19 | const struct rir_fixedarr *fixedarr = &expr->fixedarr; 20 | LLVMTypeRef member_type = bllvm_type_from_rir_type(fixedarr->member_type, ctx); 21 | // can be NULL if there are no args 22 | LLVMValueRef *vals = bllvm_value_arr_to_values(&fixedarr->members, ctx); 23 | LLVMValueRef llvm_constarr = LLVMConstArray( 24 | member_type, 25 | vals, 26 | fixedarr->size 27 | ); 28 | return llvm_constarr; 29 | } 30 | 31 | LLVMValueRef bllvm_compile_fixedarrsize( 32 | const struct rir_expression *expr, 33 | struct llvm_traversal_ctx *ctx) 34 | { 35 | RF_ASSERT(expr->type == RIR_EXPRESSION_FIXEDARRSIZE, "unexpexted expression"); 36 | return bllvm_value_from_rir_value_or_die(&expr->val, ctx); 37 | } 38 | 39 | struct LLVMOpaqueValue *bllvm_compile_objidx( 40 | const struct rir_expression *expr, 41 | struct llvm_traversal_ctx *ctx) 42 | { 43 | RF_ASSERT( 44 | rir_type_is_array(expr->objidx.objmemory->type), 45 | "You can only get an index to an array type" 46 | ); 47 | LLVMValueRef llvm_idxval = bllvm_value_from_rir_value_or_die( 48 | expr->objidx.idx, 49 | ctx 50 | ); 51 | LLVMValueRef indices[] = { 52 | LLVMConstInt(LLVMInt32TypeInContext(ctx->llvm_context), DEFAULT_PTR_ADDRESS_SPACE, 53 | DEFAULT_PTR_ADDRESS_SPACE), 54 | llvm_idxval 55 | }; 56 | LLVMValueRef gep = LLVMBuildGEP( 57 | ctx->builder, 58 | bllvm_value_from_rir_value_or_die(expr->objidx.objmemory, ctx), 59 | indices, 60 | 2, 61 | "" 62 | ); 63 | return LLVMBuildLoad(ctx->builder, gep, ""); 64 | } 65 | -------------------------------------------------------------------------------- /src/backend/llvm_arrays.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_ARRAYS_H 2 | #define LFR_BACKEND_LLVM_ARRAYS_H 3 | 4 | struct LLVMOpaqueValue; 5 | struct llvm_traversal_ctx; 6 | struct rir_expression; 7 | struct rir_fixedarr; 8 | struct rir; 9 | 10 | struct LLVMOpaqueValue *bllvm_compile_fixedarr( 11 | const struct rir_expression *expr, 12 | struct llvm_traversal_ctx *ctx 13 | ); 14 | 15 | struct LLVMOpaqueValue *bllvm_compile_fixedarrsize( 16 | const struct rir_expression *expr, 17 | struct llvm_traversal_ctx *ctx 18 | ); 19 | 20 | struct LLVMOpaqueValue *bllvm_compile_objidx( 21 | const struct rir_expression *expr, 22 | struct llvm_traversal_ctx *ctx 23 | ); 24 | #endif 25 | -------------------------------------------------------------------------------- /src/backend/llvm_conversion.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_CONVERSION_H 2 | #define LFR_BACKEND_LLVM_CONVERSION_H 3 | 4 | struct LLVMOpaqueValue; 5 | struct rir_expression; 6 | struct llvm_traversal_ctx; 7 | 8 | struct LLVMOpaqueValue *bllvm_compile_conversion(const struct rir_expression *expr, 9 | struct llvm_traversal_ctx *ctx); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/backend/llvm_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_FUNCTIONS_H 2 | #define LFR_BACKEND_LLVM_FUNCTIONS_H 3 | 4 | #include 5 | 6 | struct LLVMOpaqueModule; 7 | struct LLVMOpaqueBasicBlock; 8 | struct LLVMOpaqueValue; 9 | struct LLVMOpaqueType; 10 | 11 | struct rir; 12 | struct ast_node; 13 | struct rir_function; 14 | struct rir_call; 15 | struct llvm_traversal_ctx; 16 | 17 | struct LLVMOpaqueValue *bllvm_compile_functioncall(const struct rir_call *call, 18 | struct llvm_traversal_ctx *ctx); 19 | 20 | /** 21 | * Returns the LLVMTypeRef of an LLVMValueRef that's a function 22 | */ 23 | struct LLVMOpaqueType *bllvm_function_type(struct LLVMOpaqueValue *fn); 24 | 25 | bool bllvm_create_module_functions(struct rir *r, struct llvm_traversal_ctx *ctx); 26 | #endif 27 | -------------------------------------------------------------------------------- /src/backend/llvm_globals.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_GLOBALS_H 2 | #define LFR_BACKEND_LLVM_GLOBALS_H 3 | 4 | #include 5 | #include 6 | 7 | struct llvm_traversal_ctx; 8 | struct rir; 9 | struct RFstring; 10 | struct LLVMOpaqueValue; 11 | 12 | bool bllvm_create_globals(struct llvm_traversal_ctx *ctx); 13 | bool bllvm_create_global_functions(struct llvm_traversal_ctx *ctx); 14 | bool bllvm_create_module_types(struct rir *r, struct llvm_traversal_ctx *ctx); 15 | bool bllvm_create_module_globals(struct rir* r, struct llvm_traversal_ctx *ctx); 16 | 17 | struct LLVMOpaqueValue *bllvm_create_global_const_string( 18 | const struct RFstring *string_name, 19 | const struct RFstring *string_val, 20 | struct llvm_traversal_ctx *ctx 21 | ); 22 | struct LLVMOpaqueValue *bllvm_create_global_const_string_with_hash( 23 | const struct RFstring *string_name, 24 | const struct RFstring *string_val, 25 | uint32_t hash, 26 | struct llvm_traversal_ctx *ctx 27 | ); 28 | 29 | struct LLVMOpaqueValue *bllvm_literal_to_global_string( 30 | const struct RFstring *lit, 31 | struct llvm_traversal_ctx *ctx 32 | ); 33 | 34 | /** 35 | * @returns the global string for "true" or "false" 36 | */ 37 | struct LLVMOpaqueValue *bllvm_get_boolean_str( 38 | bool boolean, 39 | struct llvm_traversal_ctx *ctx 40 | ); 41 | #endif 42 | -------------------------------------------------------------------------------- /src/backend/llvm_operators.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_OPERATORS_H 2 | #define LFR_BACKEND_LLVM_OPERATORS_H 3 | 4 | struct LLVMOpaqueValue; 5 | struct rir_expression; 6 | struct llvm_traversal_ctx; 7 | 8 | struct LLVMOpaqueValue *bllvm_compile_comparison(const struct rir_expression *expr, 9 | struct llvm_traversal_ctx *ctx); 10 | struct LLVMOpaqueValue *bllvm_compile_rirbop(const struct rir_expression *expr, 11 | struct llvm_traversal_ctx *ctx); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/backend/llvm_values.c: -------------------------------------------------------------------------------- 1 | #include "llvm_values.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "llvm_ast.h" 11 | #include "llvm_utils.h" 12 | 13 | void *bllvm_value_from_rir_value( 14 | const struct rir_value *v, 15 | struct llvm_traversal_ctx *ctx) 16 | { 17 | // constant values are easy 18 | if (v->category == RIR_VALUE_CONSTANT) { 19 | return bllvm_compile_constant(&v->constant, v->type, ctx); 20 | } 21 | // so are string literals 22 | if (v->category == RIR_VALUE_LITERAL) { 23 | return bllvm_compile_literal(&v->literal, ctx); 24 | } 25 | // otherwise search the mapping 26 | void *ret = strmap_get(&ctx->valmap, &v->id); 27 | if (!ret) { 28 | // if not found in rir val to llvm map, it may not have been added yet. 29 | // This can happen for function arguments so check if value is one 30 | int arg_idx; 31 | if ((arg_idx = rir_fndef_value_to_argnum(ctx->current_rfn, v)) != -1) { 32 | ret = LLVMGetParam(ctx->current_function, arg_idx); 33 | // also add it to the rir val to llvm map 34 | if (!llvm_traversal_ctx_map_llvmval(ctx, v, ret)) { 35 | RF_ERROR("Failed to add a rir argument to rir value to llvm mapping"); 36 | ret = NULL; 37 | } 38 | } // else it's a failure, with ret == NULL 39 | } 40 | return ret; 41 | } 42 | 43 | void *bllvm_value_from_rir_value_or_die( 44 | const struct rir_value *v, 45 | struct llvm_traversal_ctx *ctx) 46 | { 47 | struct LLVMOpaqueValue *ret = bllvm_value_from_rir_value(v, ctx); 48 | RF_ASSERT_OR_CRITICAL(ret, return NULL, "Mapping from rir value to llvm value was not found"); 49 | return ret; 50 | } 51 | 52 | struct LLVMOpaqueValue **bllvm_value_arr_to_values( 53 | const struct value_arr *arr, 54 | struct llvm_traversal_ctx *ctx) 55 | { 56 | llvm_traversal_ctx_reset_values(ctx); 57 | struct rir_value **val; 58 | LLVMValueRef llvm_val; 59 | darray_foreach(val, *arr) { 60 | llvm_val = bllvm_value_from_rir_value_or_die(*val, ctx); 61 | llvm_traversal_ctx_add_value(ctx, llvm_val); 62 | } 63 | return llvm_traversal_ctx_get_values(ctx); 64 | } 65 | -------------------------------------------------------------------------------- /src/backend/llvm_values.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_BACKEND_LLVM_VALUES_H 2 | #define LFR_BACKEND_LLVM_VALUES_H 3 | 4 | struct rir_value; 5 | struct LLVMOpaqueValue; 6 | struct llvm_traversal_ctx; 7 | struct value_arr; 8 | 9 | void *bllvm_value_from_rir_value(const struct rir_value *v, struct llvm_traversal_ctx *ctx); 10 | void *bllvm_value_from_rir_value_or_die(const struct rir_value *v, struct llvm_traversal_ctx *ctx); 11 | struct LLVMOpaqueValue **bllvm_value_arr_to_values(const struct value_arr *arr, 12 | struct llvm_traversal_ctx *ctx); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/info/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/info.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/msg.c") 3 | -------------------------------------------------------------------------------- /src/inplocation.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | bool inplocation_init(struct inplocation *loc, 7 | struct inpfile *f, 8 | char *sp, char *ep) 9 | { 10 | loc->start.p = sp; 11 | loc->end.p = ep; 12 | 13 | if (!inpstr_ptr_to_linecol(&f->str, loc->start.p, 14 | &loc->start.line, &loc->start.col)) { 15 | return false; 16 | } 17 | 18 | if (ep) { 19 | if (!inpstr_ptr_to_linecol(&f->str, ep, 20 | &loc->end.line, &loc->end.col)) { 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | i_INLINE_INS void inplocation_init_marks(struct inplocation *loc, 27 | const struct inplocation_mark *start, 28 | const struct inplocation_mark *end); 29 | 30 | void inplocation_set_start(struct inplocation *loc, 31 | const struct inplocation_mark *start) 32 | { 33 | loc->start = *start; 34 | } 35 | void inplocation_set_end(struct inplocation *loc, const struct inplocation_mark *end) 36 | { 37 | loc->end = *end; 38 | } 39 | 40 | bool inplocation_from_file_at_point(struct inplocation *loc, 41 | struct inpfile *f, 42 | char *p) 43 | { 44 | if (!inpstr_ptr_to_linecol(&f->str, p, 45 | &loc->start.line, &loc->start.col)) { 46 | ERROR("Could not create a location from a file"); 47 | return false; 48 | } 49 | loc->end.line = loc->start.line; 50 | loc->end.col = loc->start.col; 51 | 52 | return true; 53 | } 54 | 55 | bool inplocation_from_file(struct inplocation *loc, 56 | struct inpfile *f) 57 | { 58 | return inplocation_from_file_at_point(loc, f, inpstr_data(&f->str)); 59 | } 60 | 61 | 62 | i_INLINE_INS bool inplocation_mark_equal(const struct inplocation_mark *m1, 63 | const struct inplocation_mark *m2); 64 | i_INLINE_INS bool inplocation_mark_empty(const struct inplocation_mark *m); 65 | i_INLINE_INS void inplocation_copy(struct inplocation *l1, 66 | const struct inplocation *l2); 67 | i_INLINE_INS bool inplocation_equal(const struct inplocation *l1, 68 | const struct inplocation *l2); 69 | -------------------------------------------------------------------------------- /src/inpoffset.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | i_INLINE_INS void inpoffset_init(struct inpoffset *off); 4 | i_INLINE_INS void inpoffset_copy(struct inpoffset *dst, 5 | struct inpoffset *src); 6 | i_INLINE_INS void inpoffset_add(struct inpoffset *o1, 7 | struct inpoffset *o2); 8 | i_INLINE_INS void inpoffset_sub(struct inpoffset *o1, 9 | struct inpoffset *o2); 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/ir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(parser) 2 | 3 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/rir_argument.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_array.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_binaryop.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_block.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_branch.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/rir.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_call.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_common.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_constant.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_convert.c" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_expression.c" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_function.c" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_global.c" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_loops.c" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_object.c" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_process.c" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_process_cond.c" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_process_match.c" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_strmap.c" 22 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_type.c" 23 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_typedef.c" 24 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_unaryop.c" 25 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_utils.c" 26 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_value.c" 27 | "${CMAKE_CURRENT_SOURCE_DIR}/rir_variable.c") 28 | -------------------------------------------------------------------------------- /src/ir/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CreateGperfHeader) 2 | # generate hash table for the rir parser using gperf 3 | create_gperf_header(${CMAKE_CURRENT_SOURCE_DIR} rirtoken_htable.gperf rirtoken_htable.h) 4 | 5 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/rirparser.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/rirtoken.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_binaryop.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_blocks.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_expressions.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_functions.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_global.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_typedef.c" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_utils.c" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/rparse_value.c") 15 | 16 | -------------------------------------------------------------------------------- /src/ir/parser/rirtoken.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "rirtoken_htable.h" 5 | 6 | static struct RFstring strings_[] = { 7 | RF_STRING_STATIC_INIT("identifier"), 8 | RF_STRING_STATIC_INIT("constant integer"), 9 | RF_STRING_STATIC_INIT("constant float"), 10 | RF_STRING_STATIC_INIT("string literal"), 11 | 12 | RF_STRING_STATIC_INIT("{"), 13 | RF_STRING_STATIC_INIT("}"), 14 | RF_STRING_STATIC_INIT("["), 15 | RF_STRING_STATIC_INIT("]"), 16 | RF_STRING_STATIC_INIT("("), 17 | RF_STRING_STATIC_INIT(")"), 18 | RF_STRING_STATIC_INIT("\""), 19 | RF_STRING_STATIC_INIT(","), 20 | 21 | /* binary operators */ 22 | RF_STRING_STATIC_INIT("-"), 23 | RF_STRING_STATIC_INIT("*"), 24 | RF_STRING_STATIC_INIT("="), 25 | 26 | RF_STRING_STATIC_INIT(";"), 27 | 28 | /* keywords */ 29 | RF_STRING_STATIC_INIT("global"), 30 | RF_STRING_STATIC_INIT("uniondef"), 31 | RF_STRING_STATIC_INIT("typedef"), 32 | RF_STRING_STATIC_INIT("fndef"), 33 | RF_STRING_STATIC_INIT("fndecl"), 34 | RF_STRING_STATIC_INIT("identifier variable"), 35 | RF_STRING_STATIC_INIT("identifier label"), 36 | RF_STRING_STATIC_INIT("return"), 37 | RF_STRING_STATIC_INIT("branch"), 38 | RF_STRING_STATIC_INIT("condbranch"), 39 | RF_STRING_STATIC_INIT("convert"), 40 | RF_STRING_STATIC_INIT("write"), 41 | RF_STRING_STATIC_INIT("read"), 42 | RF_STRING_STATIC_INIT("call"), 43 | 44 | RF_STRING_STATIC_INIT("add"), 45 | RF_STRING_STATIC_INIT("sub"), 46 | RF_STRING_STATIC_INIT("mul"), 47 | RF_STRING_STATIC_INIT("div"), 48 | RF_STRING_STATIC_INIT("cmpeq"), 49 | RF_STRING_STATIC_INIT("cmpne"), 50 | RF_STRING_STATIC_INIT("cmpgt"), 51 | RF_STRING_STATIC_INIT("cmpge"), 52 | RF_STRING_STATIC_INIT("cmplt"), 53 | RF_STRING_STATIC_INIT("cmple") 54 | }; 55 | 56 | const struct RFstring *rir_tokentype_to_str(enum rir_token_type type) 57 | { 58 | // helps make sure that the strings array is in sync with the tokens 59 | BUILD_ASSERT(sizeof(strings_) / sizeof(struct RFstring) == RIR_TOKENS_MAX); 60 | 61 | return &strings_[type]; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/ir/parser/rirtoken_htable.gperf: -------------------------------------------------------------------------------- 1 | %compare-strncmp 2 | %readonly-tables 3 | %define lookup-function-name rir_lexer_lexeme_is_token 4 | %define hash-function-name rir_lexer_hash 5 | %delimiters=' ' 6 | struct rinternal_token { const char *name; enum rir_token_type type; }; 7 | %% 8 | # -- Keywords section -- 9 | # attempted to have TAB as delimiter but could not make it work 10 | # 11 | # keywords 12 | global RIR_TOK_GLOBAL 13 | uniondef RIR_TOK_UNIONDEF 14 | typedef RIR_TOK_TYPEDEF 15 | fndef RIR_TOK_FNDEF 16 | fndecl RIR_TOK_FNDECL 17 | # branch instructions 18 | return RIR_TOK_RETURN 19 | branch RIR_TOK_BRANCH 20 | condbranch RIR_TOK_CONDBRANCH 21 | convert RIR_TOK_CONVERT 22 | # general instructions 23 | write RIR_TOK_WRITE 24 | read RIR_TOK_READ 25 | call RIR_TOK_CALL 26 | #binaryop instructions 27 | add RIR_TOK_ADD 28 | sub RIR_TOK_SUB 29 | mul RIR_TOK_MUL 30 | div RIR_TOK_DIV 31 | cmpeq RIR_TOK_CMPEQ 32 | cmpne RIR_TOK_CMPNE 33 | cmpgt RIR_TOK_CMPGT 34 | cmpge RIR_TOK_CMPGE 35 | cmplt RIR_TOK_CMPLT 36 | cmple RIR_TOK_CMPLE 37 | #symbols 38 | { RIR_TOK_SM_OCBRACE 39 | } RIR_TOK_SM_CCBRACE 40 | [ RIR_TOK_SM_OSBRACE 41 | ] RIR_TOK_SM_CSBRACE 42 | ( RIR_TOK_SM_OPAREN 43 | ) RIR_TOK_SM_CPAREN 44 | "\"" RIR_TOK_SM_DBLQUOTE 45 | , RIR_TOK_SM_COMMA 46 | - RIR_TOK_OP_MINUS 47 | * RIR_TOK_OP_MULTI 48 | = RIR_TOK_OP_ASSIGN 49 | ; RIR_TOK_SEMICOLON 50 | -------------------------------------------------------------------------------- /src/ir/parser/rparse_global.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct rir_object *rir_parse_global(struct rir_parser *p, const struct RFstring *name) 9 | { 10 | struct token *tok = NULL; 11 | // consume 'global' 12 | if (!rir_parse_instr_start(p, rir_tokentype_to_str(RIR_TOK_GLOBAL))) { 13 | return NULL; 14 | } 15 | 16 | if (!(tok = lexer_expect_token(parser_lexer(p), RIR_TOK_IDENTIFIER))) { 17 | rirparser_synerr(p, lexer_last_token_start(parser_lexer(p)), NULL, 18 | "Expected a type identifier as first argument of 'global'."); 19 | return NULL; 20 | } 21 | struct ast_node *type_id = tok->value.value.ast; 22 | 23 | if (!lexer_expect_token(parser_lexer(p), RIR_TOK_SM_COMMA)) { 24 | rirparser_synerr(p, lexer_last_token_start(parser_lexer(p)), NULL, 25 | "Expected a ',' after the first argument of 'global'."); 26 | return NULL; 27 | } 28 | 29 | if (!(tok = lexer_expect_token(parser_lexer(p), RIR_TOK_STRING_LITERAL))) { 30 | rirparser_synerr(p, lexer_last_token_start(parser_lexer(p)), NULL, 31 | "Expected a string literal as second argument of 'global'."); 32 | return NULL; 33 | } 34 | struct ast_node *string_lit = tok->value.value.ast; 35 | 36 | // create and add it to the global literals 37 | struct rir_object *ret = rir_global_create_parsed(p, name, type_id, string_lit); 38 | if (!ret) { 39 | return NULL; 40 | } 41 | 42 | // consume the last parentheses 43 | if (!lexer_expect_token(parser_lexer(p), RIR_TOK_SM_CPAREN)) { 44 | rirparser_synerr(p, lexer_last_token_start(parser_lexer(p)), NULL, 45 | "Expected a closing ')' at the end of 'global'."); 46 | return NULL; 47 | } 48 | 49 | return ret; 50 | } 51 | -------------------------------------------------------------------------------- /src/ir/parser/rparse_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | bool rir_parse_instr_start(struct rir_parser *p, const struct RFstring *msg) 7 | { 8 | // consume instruction token 9 | lexer_curr_token_advance(parser_lexer(p)); 10 | if (!lexer_expect_token(parser_lexer(p), RIR_TOK_SM_OPAREN)) { 11 | rirparser_synerr( 12 | p, 13 | lexer_last_token_start(parser_lexer(p)), 14 | NULL, 15 | "Expected a '(' after "RFS_PF".", RFS_PA(msg) 16 | ); 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | struct rir_value *rir_parse_val_and_comma(struct rir_parser *p, const struct RFstring *msg) 23 | { 24 | struct rir_value *val = NULL; 25 | RFS_PUSH(); 26 | if (!(val = rir_parse_value(p, RFS("at "RFS_PF, RFS_PA(msg))))) { 27 | goto end; 28 | } 29 | if (!lexer_expect_token(parser_lexer(p), RIR_TOK_SM_COMMA)) { 30 | rirparser_synerr( 31 | p, 32 | lexer_last_token_start(parser_lexer(p)), 33 | NULL, 34 | "Expected a ',' after "RFS_PF".", RFS_PA(msg) 35 | ); 36 | rir_value_destroy(val, RIR_VALUE_PARSING); 37 | val = NULL; 38 | goto end; 39 | } 40 | // success 41 | end: 42 | RFS_POP(); 43 | return val; 44 | } 45 | 46 | struct rir_type *rir_parse_type_and_comma(struct rir_parser *p, const struct RFstring *msg) 47 | { 48 | struct rir_type *type = NULL; 49 | RFS_PUSH(); 50 | if (!(type = rir_parse_type(p, msg))) { 51 | goto end; 52 | } 53 | if (!lexer_expect_token(parser_lexer(p), RIR_TOK_SM_COMMA)) { 54 | rirparser_synerr( 55 | p, 56 | lexer_last_token_start(parser_lexer(p)), 57 | NULL, 58 | "Expected a ',' after "RFS_PF".", RFS_PA(msg) 59 | ); 60 | rir_type_destroy(type, rir_parser_rir(p)); 61 | type = NULL; 62 | goto end; 63 | } 64 | // success 65 | end: 66 | RFS_POP(); 67 | return type; 68 | } 69 | -------------------------------------------------------------------------------- /src/ir/rir_common.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | void rir_common_block_add(struct rir_common *c, struct rir_expression *expr) 7 | { 8 | rir_block_add_expr(c->current_block, expr); 9 | } 10 | -------------------------------------------------------------------------------- /src/ir/rir_unaryop.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | bool rir_process_unaryop(const struct ast_unaryop *op, struct rir_ctx *ctx) 13 | { 14 | struct rir_object *exprobj; 15 | const struct rir_value *opval = rir_process_ast_node_getreadval(op->operand, ctx); 16 | if (!opval) { 17 | RF_ERROR("A value should have been created for a unary operation operand"); 18 | goto fail; 19 | } 20 | switch (op->type) { 21 | case UNARYOP_AMPERSAND: 22 | RF_CRITICAL_FAIL("TODO -- not yet implemented"); 23 | break; 24 | case UNARYOP_INC: 25 | if (!(exprobj = rir_binaryop_create_nonast_obj(RIR_EXPRESSION_ADD, opval, &g_rir_const_1, RIRPOS_AST, ctx))) { 26 | RF_ERROR("Failed to create rir expression out of increase unary operation"); 27 | goto fail; 28 | } 29 | break; 30 | case UNARYOP_DEC: 31 | if (!(exprobj = rir_binaryop_create_nonast_obj(RIR_EXPRESSION_ADD, opval, &g_rir_const_m1, RIRPOS_AST, ctx))) { 32 | RF_ERROR("Failed to create rir expression out of decreate unary operation"); 33 | goto fail; 34 | } 35 | break; 36 | case UNARYOP_MINUS: 37 | if (!(exprobj = rir_binaryop_create_nonast_obj(RIR_EXPRESSION_MUL, opval, &g_rir_const_m1, RIRPOS_AST, ctx))) { 38 | RF_ERROR("Failed to create rir expression out of minus unary operation"); 39 | goto fail; 40 | } 41 | break; 42 | case UNARYOP_PLUS: 43 | RF_CRITICAL_FAIL("What was this unary op supposed to do?"); 44 | break; 45 | } 46 | // finally add the generated expression to the block and succeed 47 | rir_common_block_add(&ctx->common, &exprobj->expr); 48 | RIRCTX_RETURN_EXPR(ctx, true, exprobj); 49 | 50 | fail: 51 | RIRCTX_RETURN_EXPR(ctx, false, NULL); 52 | } 53 | -------------------------------------------------------------------------------- /src/ir/rir_variable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static bool rir_variable_init( 6 | struct rir_object *obj, 7 | struct rir_type *type, 8 | enum rir_pos pos, 9 | rir_data data 10 | ) 11 | { 12 | return rir_value_variable_init(&obj->variable.val, obj, type, pos, data); 13 | } 14 | 15 | struct rir_object *rir_variable_create( 16 | struct rir_type *type, 17 | enum rir_pos pos, 18 | rir_data data) 19 | { 20 | struct rir_object *ret = rir_object_create(RIR_OBJ_VARIABLE, rir_data_rir(data)); 21 | if (!ret) { 22 | return NULL; 23 | } 24 | if (!rir_variable_init(ret, type, pos, data)) { 25 | free(ret); 26 | ret = NULL; 27 | } 28 | return ret; 29 | } 30 | 31 | void rir_variable_deinit(struct rir_variable *var) 32 | { 33 | rir_value_deinit(&var->val); 34 | } 35 | 36 | i_INLINE_INS struct rir_type *rir_variable_type(struct rir_variable *v); 37 | -------------------------------------------------------------------------------- /src/lexer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CreateGperfHeader) 2 | # generate hash table for the parser using gperf 3 | create_gperf_header(${CMAKE_CURRENT_SOURCE_DIR} tokens_htable.gperf tokens_htable.h) 4 | 5 | rf_target_and_test_sources(refu test_refu_helper PUBLIC 6 | "${CMAKE_CURRENT_SOURCE_DIR}/lexer.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/tokens.c") 8 | -------------------------------------------------------------------------------- /src/lexer/common.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_LEXER_COMMON_H 2 | #define LFR_LEXER_COMMON_H 3 | #define lexer_synerr(lexer_, start_, end_, ...) \ 4 | do { \ 5 | i_info_ctx_add_msg((lexer_)->info, \ 6 | MESSAGE_SYNTAX_ERROR, \ 7 | (start_), \ 8 | (end_), \ 9 | __VA_ARGS__); \ 10 | } while(0) 11 | #endif 12 | -------------------------------------------------------------------------------- /src/lexer/tokens_htable.gperf: -------------------------------------------------------------------------------- 1 | %compare-strncmp 2 | %readonly-tables 3 | %define lookup-function-name lexer_lexeme_is_token 4 | %delimiters=' ' 5 | struct internal_token { const char *name; enum token_type type; }; 6 | %% 7 | # -- Keywords section -- 8 | # attempted to have TAB as delimiter but could not make it work 9 | # 10 | # keywords 11 | const TOKEN_KW_CONST 12 | type TOKEN_KW_TYPE 13 | fn TOKEN_KW_FUNCTION 14 | class TOKEN_KW_TYPECLASS 15 | instance TOKEN_KW_TYPEINSTANCE 16 | if TOKEN_KW_IF 17 | elif TOKEN_KW_ELIF 18 | else TOKEN_KW_ELSE 19 | for TOKEN_KW_FOR 20 | in TOKEN_KW_IN 21 | return TOKEN_KW_RETURN 22 | true TOKEN_KW_TRUE 23 | false TOKEN_KW_FALSE 24 | match TOKEN_KW_MATCH 25 | module TOKEN_KW_MODULE 26 | import TOKEN_KW_IMPORT 27 | foreign_import TOKEN_KW_FOREIGN_IMPORT 28 | # special symbols 29 | : TOKEN_SM_COLON 30 | { TOKEN_SM_OCBRACE 31 | } TOKEN_SM_CCBRACE 32 | [ TOKEN_SM_OSBRACE 33 | ] TOKEN_SM_CSBRACE 34 | ( TOKEN_SM_OPAREN 35 | ) TOKEN_SM_CPAREN 36 | "\"" TOKEN_SM_DBLQUOTE 37 | => TOKEN_SM_THICKARROW 38 | # binary operators 39 | + TOKEN_OP_PLUS 40 | - TOKEN_OP_MINUS 41 | * TOKEN_OP_MULTI 42 | / TOKEN_OP_DIV 43 | = TOKEN_OP_ASSIGN 44 | # binary comparison operators 45 | == TOKEN_OP_EQ 46 | != TOKEN_OP_NEQ 47 | > TOKEN_OP_GT 48 | >= TOKEN_OP_GTEQ 49 | < TOKEN_OP_LT 50 | <= TOKEN_OP_LTEQ 51 | # unary operators 52 | & TOKEN_OP_AMPERSAND 53 | ++ TOKEN_OP_INC 54 | -- TOKEN_OP_DEC 55 | # type operators 56 | | TOKEN_OP_TYPESUM 57 | , TOKEN_OP_COMMA 58 | -> TOKEN_OP_IMPL 59 | # other binary operators 60 | . TOKEN_OP_MEMBER_ACCESS 61 | # boolean operators 62 | && TOKEN_OP_LOGIC_AND 63 | || TOKEN_OP_LOGIC_OR 64 | # bitwise operators 65 | ^ TOKEN_OP_BITWISE_XOR 66 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | struct compiler *compiler = compiler_create_with_args( 8 | LOG_TARGET_STDOUT, // rflog print to stdout 9 | true, // use stdlib 10 | argc, 11 | argv 12 | ); 13 | if (!compiler) { 14 | return 1; 15 | } 16 | 17 | if (compiler_help_requested(compiler)) { 18 | // DO not continue any further and do not deinit the compiler since 19 | // initialization did not fully conclude 20 | return 0; 21 | } 22 | 23 | if (!compiler_process(compiler)) { 24 | compiler_print_errors(compiler); 25 | return 1; // don't bother freeing stuff, just exit with error 26 | } 27 | 28 | compiler_destroy(compiler); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/ownership/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/ownership.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/ow_edge.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/ow_graph.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/ow_node.c") 5 | if (${RF_OPTION_WITH_GRAPHVIZ}) 6 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/ow_graphviz.c") 7 | endif() 8 | -------------------------------------------------------------------------------- /src/ownership/ow_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_OWNERSHIP_DEBUG_H 2 | #define LFR_OWNERSHIP_DEBUG_H 3 | 4 | /* #define OWDD(...) do{ RFS_PUSH(); printf(__VA_ARGS__); RFS_POP();}while(0) */ 5 | #define OWDD(...) 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/ownership/ow_edge.c: -------------------------------------------------------------------------------- 1 | #include "ow_edge.h" 2 | #include 3 | 4 | static void ow_edge_init(struct ow_edge *e, 5 | enum ow_edge_type type, 6 | const struct rir_expression *expr, 7 | struct ow_node *tonode, 8 | unsigned int counter) 9 | { 10 | e->type = type; 11 | e->edgeexpr = expr; 12 | e->to = tonode; 13 | e->counter = counter; 14 | } 15 | 16 | struct ow_edge *ow_edge_create(const struct rir_expression *expr, const struct RFstring *name, const struct rir_value *nodeval, unsigned int counter) 17 | { 18 | struct ow_edge *ret; 19 | struct ow_node *n; 20 | RF_MALLOC(ret, sizeof(*ret), return NULL); 21 | if (!(n = ow_node_create(name, nodeval))) { 22 | free(ret); 23 | return NULL; 24 | } 25 | ow_edge_init(ret, OW_EDGE_NORMAL, expr, n, counter); 26 | return ret; 27 | } 28 | 29 | struct ow_edge *ow_edge_create_from_node(const struct rir_expression *expr, struct ow_node *tonode, unsigned int counter) 30 | { 31 | struct ow_edge *ret; 32 | RF_MALLOC(ret, sizeof(*ret), return NULL); 33 | ow_edge_init(ret, OW_EDGE_TO_EXISTING, expr, tonode, counter); 34 | return ret; 35 | } 36 | 37 | struct ow_edge *ow_endedge_create(const struct rir_expression *expr, const struct RFstring *fnname, enum ow_end_type end_type, unsigned int counter) 38 | { 39 | struct ow_edge *ret; 40 | RF_MALLOC(ret, sizeof(*ret), return NULL); 41 | struct ow_node *n = ow_node_end_create( 42 | fnname, 43 | end_type, 44 | (expr && expr->type == RIR_EXPRESSION_CALL) ? &expr->call.name : NULL 45 | ); 46 | if (!n) { 47 | free(ret); 48 | return NULL; 49 | } 50 | RF_ASSERT(expr || end_type == OW_END_RETURN,"expression should be NULL only for returns"); 51 | ow_edge_init(ret, OW_EDGE_NORMAL, expr, n, counter); 52 | return ret; 53 | } 54 | 55 | void ow_edge_destroy(struct ow_edge *e) 56 | { 57 | if (e->type == OW_EDGE_NORMAL) { 58 | ow_node_destroy(e->to); 59 | } 60 | free(e); 61 | } 62 | -------------------------------------------------------------------------------- /src/ownership/ow_edge.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_OWNERSHIP_EDGE_H 2 | #define LFR_OWNERSHIP_EDGE_H 3 | 4 | #include "ow_node.h" 5 | 6 | enum ow_edge_type { 7 | OW_EDGE_NORMAL, 8 | OW_EDGE_TO_EXISTING, 9 | }; 10 | 11 | struct rir_expression; 12 | struct ow_edge { 13 | enum ow_edge_type type; 14 | //! Can be NULL. Example: for returns 15 | const struct rir_expression *edgeexpr; 16 | struct ow_node *to; 17 | unsigned int counter; 18 | }; 19 | 20 | /** 21 | * Create an edge to a new node by specifying a value to create a node for 22 | */ 23 | struct ow_edge *ow_edge_create(const struct rir_expression *expr, const struct RFstring *name, const struct rir_value *nodev, unsigned int counter); 24 | /** 25 | * Create an edge to an end node 26 | */ 27 | struct ow_edge *ow_endedge_create(const struct rir_expression *expr, const struct RFstring *fnname, enum ow_end_type end_type, unsigned int counter); 28 | /** 29 | * Create an edge without allocating a new node but just pointing to it 30 | */ 31 | struct ow_edge *ow_edge_create_from_node(const struct rir_expression *expr, struct ow_node *tonode, unsigned int counter); 32 | 33 | void ow_edge_destroy(struct ow_edge *e); 34 | #endif 35 | -------------------------------------------------------------------------------- /src/ownership/ow_graph.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_OWNERSHIP_GRAPH_H 2 | #define LFR_OWNERSHIP_GRAPH_H 3 | 4 | #include 5 | #include 6 | 7 | #include "ow_node.h" 8 | 9 | struct rir_expression; 10 | struct rir_object; 11 | 12 | //! Graph attributes 13 | enum graph_attrs { 14 | OW_ATTR_RETURNED = 1, 15 | OW_ATTR_PASSED = 2, 16 | }; 17 | 18 | struct ow_passed_loc { 19 | const struct rir_call *call; 20 | struct ow_node *from_node; 21 | struct ow_node *node; 22 | unsigned int idx; 23 | }; 24 | 25 | struct ow_passed_loc *ow_passed_loc_create(const struct rir_call *c, 26 | struct ow_node *n, 27 | unsigned int idx); 28 | void ow_passed_loc_destroy(struct ow_passed_loc *ploc); 29 | 30 | struct ow_graph { 31 | //! Name of the function this graph's value starts from 32 | const struct RFstring *fn_name; 33 | //! Rir object describing what this graph is for 34 | struct rir_object *obj; 35 | //! The root node of this graph 36 | struct ow_node *root; 37 | //! Set of ownership nodes that are related to the root node of the graph. 38 | //! Used to find if a node has a relation 39 | struct rf_objset_ownode set; 40 | //! Graph attributes denoting what happens to the value 41 | int graph_attrs; 42 | //! If the graph is marked as passing the value somewhere else these are the 43 | //! locations to connect to 44 | struct {darray(struct ow_passed_loc*);} passed_locations; 45 | //! The symbol table record of the rir object the graph is for 46 | struct symbol_table_record *rec; 47 | }; 48 | 49 | struct ow_graph *ow_graph_create(struct rir_object *expr, 50 | const struct RFstring *name, 51 | struct symbol_table_record *rec); 52 | void ow_graph_destroy(struct ow_graph *g); 53 | 54 | bool ow_graph_check_or_add_val(struct ow_graph *g, 55 | const struct rir_value *v, 56 | const struct rir_value *dependentv, 57 | const struct rir_expression *edgexpr); 58 | 59 | bool ow_graph_check_or_add_end(struct ow_graph *g, 60 | const struct rir_value *v, 61 | enum ow_end_type end_type, 62 | const struct rir_expression *edgexpr, 63 | unsigned int idx); 64 | 65 | void ow_graph_set_attr(struct ow_graph *g, enum graph_attrs attr); 66 | 67 | i_INLINE_DECL bool ow_graph_has_attr(const struct ow_graph *g, enum graph_attrs attr) 68 | { 69 | return RF_BITFLAG_ON(g->graph_attrs, attr); 70 | } 71 | 72 | #if RF_OPTION_WITH_GRAPHVIZ 73 | /** 74 | * Turn a graph to a graphviz dot graph 75 | */ 76 | bool ow_graph_to_graphviz(struct ow_graph *g); 77 | #endif 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/ownership/ow_graphviz.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_OWNERSHIP_GRAPHVIZ_H 2 | #define LFR_OWNERSHIP_GRAPHVIZ_H 3 | 4 | #include 5 | 6 | bool ow_graphviz_init(); 7 | void ow_graphviz_deinit(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/ownership/ow_node.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_OWNERSHIP_NODE_H 2 | #define LFR_OWNERSHIP_NODE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct rir_value; 10 | struct rir_expression; 11 | struct ow_edge; 12 | 13 | struct ow_node_full { 14 | const struct rir_value *val; 15 | }; 16 | 17 | enum ow_end_type { 18 | OW_END_RETURN, 19 | OW_END_PASSED 20 | }; 21 | 22 | struct ow_node_end { 23 | enum ow_end_type type; 24 | const struct RFstring *other_fn_name; 25 | }; 26 | 27 | enum ow_node_type { 28 | OW_NTYPE_FULL, 29 | OW_NTYPE_END, 30 | }; 31 | struct ow_node { 32 | enum ow_node_type type; 33 | const struct RFstring *fnname; 34 | struct {darray(struct ow_edge*);} edges; 35 | union { 36 | struct ow_node_full full; 37 | struct ow_node_end end; 38 | }; 39 | }; 40 | 41 | void ow_node_init(struct ow_node *n, const struct rir_value *nodeval); 42 | struct ow_node *ow_node_create(const struct RFstring *fnname, const struct rir_value *nodeval); 43 | struct ow_node *ow_node_end_create(const struct RFstring *fnname, enum ow_end_type end_type, const struct RFstring *other_fn_name); 44 | 45 | bool ow_node_connect_node(struct ow_node *n, const struct rir_expression *expr, struct ow_node *other); 46 | bool ow_node_connect_end_node(struct ow_node *n, const struct rir_expression *expr, struct ow_node *other); 47 | 48 | void ow_node_deinit(struct ow_node *n); 49 | void ow_node_destroy(struct ow_node *n); 50 | 51 | /** 52 | * Given a unique ID for this ow node graph 53 | * @warning Should be wrapped in RFS_PUSH() / RFS_POP() 54 | */ 55 | const struct RFstring *ow_node_id(const struct ow_node *n); 56 | 57 | struct ow_node *ow_node_add_val_edge(struct ow_node *n, const struct rir_value *otherval, const struct rir_expression *expr); 58 | struct ow_node *ow_node_add_end_edge(struct ow_node *n, enum ow_end_type end_type, const struct rir_expression *expr); 59 | 60 | const struct RFstring *ow_node_end_type_str(enum ow_end_type type); 61 | 62 | i_INLINE_DECL const void *ownode_objset_key(const struct ow_node *n) 63 | { 64 | return (const void*)n; 65 | } 66 | 67 | size_t ownode_objset_hashfn(const struct ow_node *n); 68 | bool ownode_objset_eqfn(const struct ow_node *n1, 69 | const struct ow_node *n2); 70 | 71 | OBJSET_DEFINE_TYPE(ownode, 72 | struct ow_node, 73 | ownode_objset_key, 74 | ownode_objset_hashfn, 75 | ownode_objset_eqfn) 76 | 77 | struct ow_node *ownode_objset_has_value(const struct rf_objset_ownode *set, const struct RFstring *fnname, const struct rir_value *v); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(recursive_descent) 2 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/parser.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/parser_common.c") 4 | -------------------------------------------------------------------------------- /src/parser/parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | i_INLINE_INS struct ast_parser *parser_common_to_astparser(const struct parser_common* c); 10 | 11 | bool ast_parser_init( 12 | struct ast_parser *p, 13 | struct inpfile *file, 14 | struct lexer *lex, 15 | struct info_ctx *info, 16 | struct front_ctx *front 17 | ) 18 | { 19 | RF_STRUCT_ZERO(p); 20 | parser_common_init(&p->cmn, PARSER_AST, front, file, lex, info); 21 | p->have_syntax_err = false; 22 | return true; 23 | } 24 | 25 | struct ast_parser *ast_parser_create( 26 | struct inpfile *f, 27 | struct lexer *lex, 28 | struct info_ctx *info, 29 | struct front_ctx *front 30 | ) 31 | { 32 | struct ast_parser *ret; 33 | RF_MALLOC(ret, sizeof(*ret), return NULL); 34 | if (!ast_parser_init(ret, f, lex, info, front)) { 35 | free(ret); 36 | return NULL; 37 | } 38 | return ret; 39 | } 40 | 41 | void ast_parser_deinit(struct ast_parser *p) 42 | { 43 | if (p->root) { 44 | // if parser has ownership of ast tree 45 | ast_node_destroy(p->root); 46 | } 47 | parser_common_deinit(&p->cmn); 48 | } 49 | 50 | void ast_parser_destroy(struct ast_parser *p) 51 | { 52 | ast_parser_deinit(p); 53 | free(p); 54 | } 55 | 56 | i_INLINE_INS void ast_parser_set_syntax_error(struct ast_parser *parser); 57 | i_INLINE_INS bool ast_parser_has_syntax_error(struct ast_parser *parser); 58 | i_INLINE_INS bool ast_parser_has_syntax_error_reset(struct ast_parser *parser); 59 | 60 | void ast_parser_info_rollback(struct ast_parser *parser) 61 | { 62 | info_ctx_rollback(parser->cmn.info); 63 | parser->have_syntax_err = false; 64 | } 65 | -------------------------------------------------------------------------------- /src/parser/parser_common.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | i_INLINE_INS void parser_common_init(struct parser_common *c, enum parser_type type, struct front_ctx *front, struct inpfile *f, struct lexer *lexer, struct info_ctx *info); 7 | i_INLINE_INS void parser_common_deinit(struct parser_common *c); 8 | 9 | void parser_destroy(struct parser_common *c) 10 | { 11 | switch (c->type) { 12 | case PARSER_AST: 13 | ast_parser_destroy(parser_common_to_astparser(c)); 14 | break; 15 | case PARSER_RIR: 16 | rir_parser_destroy(parser_common_to_rirparser(c)); 17 | break; 18 | default: 19 | RF_CRITICAL_FAIL("Illegal parser type"); 20 | break; 21 | } 22 | } 23 | 24 | void parser_common_flush_messages(struct parser_common *c) 25 | { 26 | info_ctx_flush(c->info, stdout, MESSAGE_ANY); 27 | } 28 | 29 | bool parser_parse(struct parser_common *c) 30 | { 31 | switch (c->type) { 32 | case PARSER_AST: 33 | return ast_parser_process_file(parser_common_to_astparser(c)); 34 | case PARSER_RIR: 35 | return rir_parse(parser_common_to_rirparser(c)); 36 | default: 37 | RF_CRITICAL_FAIL("Illegal parser type"); 38 | break; 39 | } 40 | return false; 41 | } 42 | 43 | struct ast_node *parser_ast_get_root(struct parser_common *c) 44 | { 45 | RF_ASSERT(c->type == PARSER_AST, "Expected ast parser"); 46 | return parser_common_to_astparser(c)->root; 47 | } 48 | 49 | struct ast_node *parser_ast_move_root(struct parser_common *c) 50 | { 51 | RF_ASSERT(c->type == PARSER_AST, "Expected ast parser"); 52 | struct ast_node *ret = parser_common_to_astparser(c)->root; 53 | parser_common_to_astparser(c)->root = NULL; 54 | return ret; 55 | } 56 | 57 | struct rir *parser_rir(struct parser_common *c) 58 | { 59 | RF_ASSERT(c->type == PARSER_RIR, "Expected rir parser"); 60 | return rir_parser_rir(parser_common_to_rirparser(c)); 61 | } 62 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/arr.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/block.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/core.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/expression.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/function.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/generics.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/identifier.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/ifexpr.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/forexpr.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/matchexpr.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/module.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/type.c" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/typeclass.c" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/vardecl.c") 15 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/arr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_ARRAY_H 2 | #define LFR_PARSER_ARRAY_H 3 | 4 | struct ast_parser; 5 | 6 | /** 7 | * single_array_specificer = "[" constant_expression "]" 8 | * array_specifier' = single_aray_specifier 9 | * / EMPTY 10 | * array_specificer = single_array_specifier array_specifier' 11 | */ 12 | struct ast_node *ast_parser_acc_arrspec(struct ast_parser *p); 13 | 14 | /** 15 | * bracket_list = "[" expression "]" 16 | */ 17 | struct ast_node *ast_parser_acc_bracketlist(struct ast_parser *p); 18 | #endif 19 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/block.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_BLOCK_H 2 | #define LFR_PARSER_BLOCK_H 3 | 4 | #include 5 | 6 | struct ast_parser; 7 | 8 | #define TOKEN_IS_BLOCK_START(tok_) ((tok_) && (tok_)->type == TOKEN_SM_OCBRACE) 9 | 10 | /** 11 | * block_element = expression 12 | * | expression_statement 13 | * 14 | * block = TOKEN_SM_OCBRACE block_element TOKEN_SM_CCBRACE 15 | */ 16 | struct ast_node *ast_parser_acc_block(struct ast_parser *p, bool expect_braces); 17 | #endif 18 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/common.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_RECURSIVE_DESCENT_COMMON_H 2 | #define LFR_PARSER_RECURSIVE_DESCENT_COMMON_H 3 | 4 | #include 5 | // TODO: Change both this and the lexer macro to something better 6 | #define parser_synerr(parser_, start_, end_, ...) \ 7 | do { \ 8 | i_info_ctx_add_msg((parser_)->cmn.info, \ 9 | MESSAGE_SYNTAX_ERROR, \ 10 | (start_), \ 11 | (end_), \ 12 | __VA_ARGS__); \ 13 | ast_parser_set_syntax_error(parser_); \ 14 | } while(0) 15 | 16 | 17 | bool ast_parser_acc_exprlist(); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/expression.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_EXPRESSION_H 2 | #define LFR_PARSER_EXPRESSION_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | struct ast_parser; 8 | 9 | #define EXPR_ELEMENT_START "an expression" 10 | 11 | /** 12 | * expression = expr_level1 expression' 13 | * 14 | * expression' = TOKEN_OP_ASSIGN expr_level1 expression' 15 | * / EMPTY 16 | * 17 | * expr_level1 = expr_level2 expr_level1' 18 | * 19 | * expr_level1' = TOKEN_OP_PLUS expr_level2 expr_level1' 20 | * / TOKEN_OP_MINUS expr_level2 expr_level1' 21 | * / EMPTY 22 | * 23 | * expr_level2 = expr_level3 expr_level2' 24 | * 25 | * expr_level2' = TOKEN_OP_MULTI expr_level3 expr_level2' 26 | * / TOKEN_OP_DIV expr_level3 expr_level2' 27 | * / EMPTY 28 | * 29 | * expr_prefix_unary_ops = TOKEN_OP_AMPERSAND 30 | * / TOKEN_OP_INC 31 | * / TOKEN_OP_DEC 32 | * 33 | * expr_postfix_unary_ops = TOKEN_OP_INC 34 | * / TOKEN_OP_DEC 35 | * 36 | * expr_level3 = expr_factor 37 | * 38 | * expr_factor = expr_prefix_unary_ops expr_element 39 | * / expr_element expr_postfix_unary_ops 40 | * / expr_element 41 | * 42 | * expr_element = string_literal 43 | * / numeric_constant 44 | * / identifier 45 | * / function_call 46 | * / array_reference 47 | * / TOKEN_SM_OPAREN expression TOKEN_SM_CPAREN 48 | */ 49 | struct ast_node *ast_parser_acc_expression(struct ast_parser *p); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/forexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_FOR_EXPRESSION_H 2 | #define LFR_PARSER_FOR_EXPRESSION_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_parser; 8 | 9 | #define TOKEN_IS_POSSIBLE_FOREXPR(tok_) (tok_ && (tok_)->type == TOKEN_KW_FOR) 10 | 11 | /** 12 | * for_expresion = TOKEN_KW_FOR identifier TOKEN_KW_IN identifier TOKEN_SM_OCBRACE block TOKEN_SM_CCBRACE 13 | */ 14 | struct ast_node *ast_parser_acc_forexpr(struct ast_parser *p); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/generics.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_GENERICS_H 2 | #define LFR_PARSER_GENERICS_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | struct ast_parser; 8 | 9 | #define GENRATTR_START_COND(tok_) \ 10 | ((tok_) && (tok_)->type == TOKEN_OP_LT) 11 | 12 | #define GENRDECL_START_COND(tok_) \ 13 | ((tok_) && (tok_)->type == TOKEN_OP_LT) 14 | 15 | /** 16 | * generic_declaration = "<" generic_decls ">" 17 | * 18 | * generic_decls = generic_decl_single generic_decls' 19 | * 20 | * generic_decls' = TOKEN_OP_COMMA generic_decl_single generic_decls' 21 | * / EMPTY 22 | * 23 | * @TODO: Think what the first identifier should be here 24 | * In the tests, "type" was making the test fail since it's a keyword 25 | * generic_decl_single = identifier identifier 26 | */ 27 | struct ast_node *ast_parser_acc_genrdecl(struct ast_parser *p); 28 | 29 | /** 30 | * generic_attributes = "<" generic_attribute ">" 31 | * 32 | * generic_attribute = generic_attribute_single generic_attribute' 33 | * 34 | * generic_attribute' = TOKEN_OP_COMMA generic_attribute_single generic_attribute' 35 | * / EMPTY 36 | * 37 | * generic_attribute_single = "(" type_description ")" 38 | * / annotated_identifier 39 | * 40 | */ 41 | struct ast_node *ast_parser_acc_genrattr(struct ast_parser *p, bool expect_it); 42 | #endif 43 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/identifier.c: -------------------------------------------------------------------------------- 1 | #include "identifier.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "arr.h" 7 | #include "generics.h" 8 | 9 | #include "common.h" 10 | 11 | i_INLINE_INS struct ast_node *ast_parser_acc_identifier(struct ast_parser *p); 12 | struct ast_node *ast_parser_acc_xidentifier(struct ast_parser *p, bool expect_it) 13 | { 14 | struct ast_node *id; 15 | struct ast_node *xid; 16 | struct ast_node *genr; 17 | struct ast_node *arrspec; 18 | bool is_const = false; 19 | const struct inplocation_mark *start; 20 | const struct inplocation_mark *end; 21 | 22 | struct token *tok = lexer_lookahead(parser_lexer(p), 1); 23 | if (!tok) { 24 | return NULL; 25 | } 26 | 27 | // parsing logic for the annotations to the identifier here 28 | if (tok->type == TOKEN_KW_CONST) { 29 | //consume 'const' 30 | lexer_curr_token_advance(parser_lexer(p)); 31 | 32 | is_const = true; 33 | start = token_get_start(tok); 34 | tok = lexer_lookahead(parser_lexer(p), 1); 35 | if (!tok) { 36 | parser_synerr(p, lexer_last_token_end(parser_lexer(p)), NULL, 37 | "Expected an identifier after const"); 38 | return NULL; 39 | } 40 | } else { 41 | start = token_get_start(tok); 42 | } 43 | 44 | if (tok->type != TOKEN_IDENTIFIER) { 45 | if (expect_it) { 46 | parser_synerr(p, token_get_end(tok), NULL, 47 | "Expected an identifier"); 48 | } 49 | return NULL; 50 | } 51 | //consume identifier 52 | lexer_curr_token_advance(parser_lexer(p)); 53 | id = lexer_token_get_value(parser_lexer(p), tok); 54 | end = ast_node_endmark(id); 55 | 56 | tok = lexer_lookahead(parser_lexer(p), 1); 57 | genr = ast_parser_acc_genrattr(p, false); 58 | if (!genr && ast_parser_has_syntax_error(p)) { 59 | return NULL; 60 | } 61 | if (genr) { 62 | end = ast_node_endmark(genr); 63 | } 64 | 65 | arrspec = ast_parser_acc_arrspec(p); 66 | if (!arrspec && ast_parser_has_syntax_error(p)) { 67 | goto fail_free_genr; 68 | } 69 | if (arrspec) { 70 | end = ast_node_endmark(arrspec); 71 | } 72 | 73 | xid = ast_xidentifier_create(start, end, id, is_const, genr, arrspec); 74 | if (!xid) { 75 | RF_ERRNOMEM(); 76 | goto fail_free_arrspec; 77 | } 78 | 79 | return xid; 80 | 81 | fail_free_arrspec: 82 | if (arrspec) { 83 | ast_node_destroy(arrspec); 84 | } 85 | fail_free_genr: 86 | if (genr) { 87 | ast_node_destroy(genr); 88 | } 89 | return NULL; 90 | } 91 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/identifier.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_IDENTIFIER_H 2 | #define LFR_PARSER_IDENTIFIER_H 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | struct ast_parser; 9 | 10 | #define XIDENTIFIER_START_STR "'const' or identifier" 11 | #define XIDENTIFIER_START_COND(tok_) \ 12 | ((tok_) && \ 13 | ((tok_)->type == TOKEN_KW_CONST || (tok_)->type == TOKEN_IDENTIFIER)) 14 | 15 | // start of an annotated identifier that does have to start with some special 16 | // attributes 17 | #define XIDENTIFIER_START_SPECIAL_COND(tok_) \ 18 | (tok_ && (tok_)->type == TOKEN_KW_CONST) 19 | 20 | i_INLINE_DECL struct ast_node *ast_parser_acc_identifier(struct ast_parser *p) 21 | { 22 | struct token *tok; 23 | tok = lexer_lookahead(parser_lexer(p), 1); 24 | if (!tok || tok->type != TOKEN_IDENTIFIER) { 25 | return NULL; 26 | } 27 | // consume the identifier token and return it 28 | lexer_curr_token_advance(parser_lexer(p)); 29 | return lexer_token_get_value(parser_lexer(p), tok); 30 | } 31 | 32 | /** 33 | * annotated_identifier = ["const"] identifier [generic_attributes] [array_specifier] 34 | */ 35 | struct ast_node *ast_parser_acc_xidentifier(struct ast_parser *p, bool expect_it); 36 | #endif 37 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/ifexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_IF_EXPRESSION_H 2 | #define LFR_PARSER_IF_EXPRESSION_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_parser; 8 | 9 | #define TOKEN_IS_POSSIBLE_IFEXPR(tok_) (tok_ && (tok_)->type == TOKEN_KW_IF) 10 | 11 | /** 12 | * conditional_branch = expression TOKEN_SM_OCBRACE block TOKEN_SM_CCBRACE 13 | */ 14 | 15 | /** 16 | * fall_through_branch = TOKEN_KW_ELSE conditional_branch 17 | * 18 | * if_expression = TOKEN_KW_IF conditional_branch if_expression' [fall_through_branch] 19 | * 20 | * if_expression' = TOKEN_KW_ELIF conditional_branch if_expression' 21 | * / EMPTY 22 | */ 23 | struct ast_node *ast_parser_acc_ifexpr(struct ast_parser *p, enum token_type if_type); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/matchexpr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_MATCH_EXPRESSION_H 2 | #define LFR_PARSER_MATCH_EXPRESSION_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_parser; 8 | 9 | #define TOKEN_IS_POSSIBLE_MATCH_EXPRESSION(tok_) (tok_ && (tok_)->type == TOKEN_KW_MATCH) 10 | 11 | /** 12 | * conditional_branch = expression TOKEN_SM_OCBRACE block TOKEN_SM_CCBRACE 13 | */ 14 | 15 | /** 16 | * match_pattern = type_description 17 | * match_case = match_pattern TOKEN_SM_THICKARROW expression 18 | * / NIL 19 | * match_cases = match_case match_cases 20 | * match_expression = TOKEN_KW_MATCH identifier TOKEN_SM_OCBRACE match_cases TOKEN_SM_CCBRACE 21 | * 22 | * @param p The parser instance 23 | * @param have_header True if it's an expression with a match(..) { } header 24 | * and false if it's a body of a function 25 | * @param expect_it If true, failure to parse is an error. 26 | * @return The parsed match expression node. 27 | */ 28 | struct ast_node *ast_parser_acc_matchexpr(struct ast_parser *p, 29 | bool have_header, 30 | bool expect_it); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/module.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_MODULE_H 2 | #define LFR_PARSER_MODULE_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_parser; 8 | 9 | #define TOKEN_IS_IMPORT(i_tok_) ( \ 10 | (i_tok_) && \ 11 | ((i_tok_)->type == TOKEN_KW_IMPORT || (i_tok_)->type == TOKEN_KW_FOREIGN_IMPORT)) 12 | 13 | #define TOKEN_IS_MODULE_START(tok_) ((tok_) && (tok_)->type == TOKEN_KW_MODULE) 14 | 15 | /** 16 | * import_statement = (import | foreign_import) identifier_list 17 | */ 18 | struct ast_node *ast_parser_acc_import(struct ast_parser *p); 19 | 20 | /** 21 | * module_statements = import_statement 22 | * / function_implementation 23 | * / function_declaration 24 | * / type_declaration 25 | * / NULL 26 | * 27 | * module_block = TOKEN_SM_OCBRACE module_statements TOKEN_SM_CCBRACE 28 | * 29 | * module_args = TOKEN_KW_OPAREN type_description TOKEN_KW_CPAREN 30 | * / NULL 31 | * 32 | * module = TOKEN_KW_MODULE identifier module_args module_block 33 | */ 34 | struct ast_node *ast_parser_acc_module(struct ast_parser *p); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/type.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_TYPE_H 2 | #define LFR_PARSER_TYPE_H 3 | 4 | #include 5 | 6 | struct ast_node; 7 | struct ast_parser; 8 | 9 | #define TYPETERM_START_STR "'(' or identifier" 10 | #define TYPEFACTOR_START_STR "'(' or identifier" 11 | #define TYPEELEMENT_START_STR "'(' or identifier" 12 | #define TYPEDESC_START_STR "'(' or identifier" 13 | 14 | #define TYPEDESC_START_COND(tok_) \ 15 | ((tok_) && \ 16 | ((tok_)->type == TOKEN_SM_OPAREN || (tok_)->type == TOKEN_IDENTIFIER)) 17 | 18 | /** 19 | * type_leaf = identifier TOKEN_SM_COLON annotated_identifier 20 | * / identifier TOKEN_SM_COLON TOKEN_SM_OPAREN type_description TOKEN_SM_CPAREN 21 | * / annotated_identifier 22 | */ 23 | struct ast_node *ast_parser_acc_typeleaf(struct ast_parser *p); 24 | 25 | /** 26 | * For the parser accepting a type description is a generic function to insert 27 | * into the parsing of types. The syntax rules can be seen below. This can return 28 | * a node of either type_leaf or type_operator. 29 | * 30 | * type_description = type_term type_description' 31 | * 32 | * type_description' = TOKEN_OP_IMPL type_term type_description' 33 | * / EMPTY 34 | * 35 | * type_term = type_factor type_term' 36 | * 37 | * type_term' = TOKEN_OP_TYPESUM type_factor type_term' 38 | * / EMPTY 39 | * 40 | * type_factor = type_element type_factor' 41 | * 42 | * type_factor' = TOKEN_OP_PRODUCT type_element type_factor' 43 | * / EMPTY 44 | * type_element = TOKEN_SM_OPAREN type_description TOKEN_SM_CPAREN 45 | * / type_leaf 46 | * 47 | * Set of possible first tokens for a type description 48 | * FIRST(type_description) = { identifier, TOKEN_SM_OPAREN } 49 | */ 50 | struct ast_node *ast_parser_acc_typedesc(struct ast_parser *p); 51 | /** 52 | * Simple wrapper over @ref parser_acc_typedesc() that will create 53 | * a root type description node which corresponds to ast_typedesc. The main 54 | * difference is that such a node has a symbol table 55 | */ 56 | struct ast_node *ast_parser_acc_typedesc_top(struct ast_parser *p); 57 | 58 | #define TOKEN_IS_TYPEDECL_START(tok_) ((tok_) && (tok_)->type == TOKEN_KW_TYPE) 59 | 60 | /** 61 | * type_declaration = TOKEN_KW_TYPE TOKEN_SM_OCBRACE type_description TOKEN_SM_CCBRACE 62 | */ 63 | struct ast_node *ast_parser_acc_typedecl(struct ast_parser *p); 64 | #endif 65 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/typeclass.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_TYPECLASS_H 2 | #define LFR_PARSER_TYPECLASS_H 3 | 4 | struct ast_node; 5 | struct ast_parser; 6 | 7 | /** 8 | * typeclass = TOKEN_KW_TYPECLASS identifier [generic_declaration] 9 | * TOKEN_SM_OCBRACE functions_declarations TOKEN_SM_CCBRACE 10 | */ 11 | struct ast_node *ast_parser_acc_typeclass(struct ast_parser *p); 12 | 13 | /** 14 | * typeinstance = TOKEN_KW_INSTANCE identifier identifier [generic_declararion] 15 | * TOKEN_SM_OCBRACE function_implementations TOKEN_SM_CCBRACE 16 | */ 17 | struct ast_node *ast_parser_acc_typeinstance(struct ast_parser *p); 18 | #endif 19 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/vardecl.c: -------------------------------------------------------------------------------- 1 | #include "vardecl.h" 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include "common.h" 12 | #include "type.h" 13 | #include "expression.h" 14 | 15 | // parsing a variable declaration is basically like a type leaf 16 | struct ast_node *ast_parser_acc_vardecl(struct ast_parser *p) 17 | { 18 | lexer_push(parser_lexer(p)); 19 | 20 | struct ast_node *desc = ast_parser_acc_typeleaf(p); 21 | if (!desc) { 22 | goto fail; 23 | } 24 | 25 | struct ast_node *n = ast_vardecl_create( 26 | ast_node_startmark(desc), 27 | ast_node_endmark(desc), 28 | desc 29 | ); 30 | if (!n) { 31 | RF_ERRNOMEM(); 32 | goto fail; 33 | } 34 | 35 | lexer_pop(parser_lexer(p)); 36 | return n; 37 | 38 | fail: 39 | lexer_rollback(parser_lexer(p)); 40 | return NULL; 41 | } 42 | -------------------------------------------------------------------------------- /src/parser/recursive_descent/vardecl.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_PARSER_VARIABLE_DECLARATION_H 2 | #define LFR_PARSER_VARIABLE_DECLARATION_H 3 | 4 | struct ast_node; 5 | struct ast_parser; 6 | 7 | #define TOKENS_ARE_POSSIBLE_VARDECL(tok1_, tok2_) \ 8 | (tok1_ && tok2_ && (tok1_)->type == TOKEN_IDENTIFIER && \ 9 | (tok2_)->type == TOKEN_SM_COLON) 10 | 11 | /** 12 | * variable_declaration = type_leaf [ TOKEN_OP_ASSIGN expression] 13 | */ 14 | struct ast_node *ast_parser_acc_vardecl(struct ast_parser *p); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/serializer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/serializer.c") 2 | if (${RF_OPTION_HAVE_JSONC}) 3 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/astprinter.c") 4 | endif() 5 | -------------------------------------------------------------------------------- /src/serializer/astprinter.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_SERIALIZER_ASTPRINTER_H 2 | #define LFR_SERIALIZER_ASTPRINTER_H 3 | 4 | #include 5 | #include 6 | 7 | struct ast_node; 8 | struct inpfile; 9 | 10 | /** 11 | * Prints the ast in json format in the specified file stream (can be stdout) 12 | */ 13 | bool ast_output_to_file(const struct ast_node *root, 14 | FILE *f, 15 | const struct inpfile *inf); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/serializer/serializer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include "astprinter.h" 11 | 12 | bool serializer_init(struct serializer *sr, struct compiler_args *args) 13 | { 14 | sr->args = args; 15 | return true; 16 | } 17 | 18 | struct serializer *serializer_create(struct compiler_args *args) 19 | { 20 | struct serializer *sr; 21 | RF_MALLOC(sr, sizeof(*sr), return NULL); 22 | 23 | if (!serializer_init(sr, args)) { 24 | free(sr); 25 | return NULL; 26 | } 27 | 28 | return sr; 29 | } 30 | 31 | void serializer_destroy(struct serializer *sr) 32 | { 33 | free(sr); 34 | } 35 | 36 | bool serializer_process(struct serializer *sr, 37 | const struct module *mod) 38 | { 39 | #if RF_OPTION_HAVE_JSONC 40 | struct RFstring *out_name; 41 | static const struct RFstring s_stdout = RF_STRING_STATIC_INIT("stdout"); 42 | if (compiler_args_output_ast(sr->args, &out_name)) { 43 | FILE *f; 44 | if (rf_string_equal(&s_stdout, out_name)) { 45 | f = stdout; 46 | } else { 47 | f = rf_fopen(out_name, "wb"); 48 | if (!f) { 49 | return false; 50 | } 51 | } 52 | // for now just put it stdout, we will configure via compiler-args 53 | if (!ast_output_to_file(mod->node, f, module_get_file(mod))) { 54 | return SERC_FAILURE; 55 | } 56 | if (f != stdout) { 57 | fclose(f); 58 | } 59 | return SERC_SUCCESS_EXIT; 60 | } 61 | #endif 62 | return SERC_SUCCESS_CONTINUE; 63 | } 64 | -------------------------------------------------------------------------------- /src/types/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CreateGperfHeader) 2 | # generate hash table for the elementary types using gperf 3 | create_gperf_header(${CMAKE_CURRENT_SOURCE_DIR} elementary_types_htable.gperf elementary_types_htable.h) 4 | 5 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/type.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/type_arr.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/type_comparisons.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/type_creation.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/type_elementary.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/type_function.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/type_operators.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/type_utils.c") 13 | -------------------------------------------------------------------------------- /src/types/elementary_types_htable.gperf: -------------------------------------------------------------------------------- 1 | %compare-strncmp 2 | %readonly-tables 3 | %define lookup-function-name types_string_is_elementary 4 | %delimiters=' ' 5 | struct gperf_elementary_type {const char *name; enum elementary_type type; }; 6 | %% 7 | # -- Keywords section -- 8 | # attempted to have TAB as delimiter but could not make it work 9 | # 10 | # keywords 11 | int ELEMENTARY_TYPE_INT 12 | uint ELEMENTARY_TYPE_UINT 13 | u8 ELEMENTARY_TYPE_UINT_8 14 | i8 ELEMENTARY_TYPE_INT_8 15 | u16 ELEMENTARY_TYPE_UINT_16 16 | i16 ELEMENTARY_TYPE_INT_16 17 | u32 ELEMENTARY_TYPE_UINT_32 18 | i32 ELEMENTARY_TYPE_INT_32 19 | u64 ELEMENTARY_TYPE_UINT_64 20 | i64 ELEMENTARY_TYPE_INT_64 21 | f32 ELEMENTARY_TYPE_FLOAT_32 22 | f64 ELEMENTARY_TYPE_FLOAT_64 23 | string ELEMENTARY_TYPE_STRING 24 | bool ELEMENTARY_TYPE_BOOL 25 | nil ELEMENTARY_TYPE_NIL 26 | -------------------------------------------------------------------------------- /src/types/type_function.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | i_INLINE_INS bool type_is_function(const struct type *t); 9 | i_INLINE_INS bool type_is_callable(const struct type *t); 10 | i_INLINE_INS const struct type *type_callable_get_argtype(const struct type *t); 11 | i_INLINE_INS struct type *type_callable_get_rettype(const struct type *t); 12 | 13 | static const struct RFstring s_function_ = RF_STRING_STATIC_INIT("function"); 14 | static const struct RFstring s_ctor_ = RF_STRING_STATIC_INIT("constructor"); 15 | 16 | struct type *type_function_get_argtype(const struct type *t) 17 | { 18 | RF_ASSERT(type_is_function(t) && darray_size(t->operator.operands) == 2, 19 | "Non function type detected"); 20 | return darray_item(t->operator.operands, 0); 21 | } 22 | 23 | struct type *type_function_get_rettype(const struct type *t) 24 | { 25 | RF_ASSERT(type_is_function(t) && darray_size(t->operator.operands) == 2, 26 | "Non function type detected"); 27 | return darray_item(t->operator.operands, 1); 28 | } 29 | 30 | const struct RFstring *type_callable_category_str(const struct type *t) 31 | { 32 | RF_ASSERT(type_is_callable(t), "Non callable type detected"); 33 | if (type_is_function(t)) { 34 | return &s_function_; 35 | } 36 | return &s_ctor_; 37 | } 38 | 39 | void type_function_init( 40 | struct type *t, 41 | struct type *arg_type, 42 | struct type *ret_type 43 | ) 44 | { 45 | t->category = TYPE_CATEGORY_OPERATOR; 46 | t->operator.type = TYPEOP_IMPLICATION; 47 | 48 | darray_append(t->operator.operands, arg_type); 49 | darray_append(t->operator.operands, ret_type); 50 | } 51 | 52 | struct type *type_function_create( 53 | struct module *m, 54 | struct type *arg_type, 55 | struct type *ret_type 56 | ) 57 | { 58 | struct type *t; 59 | t = type_alloc(m); 60 | if (!t) { 61 | RF_ERROR("Type allocation failed"); 62 | return NULL; 63 | } 64 | type_function_init(t, arg_type, ret_type); 65 | return t; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/types/type_operators.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void type_operator_add_operand(struct type_operator *p, struct type *c) 5 | { 6 | if (p != &c->operator) { 7 | darray_append(p->operands, c); 8 | } 9 | } 10 | i_INLINE_INS void type_add_operand(struct type *p, struct type *c); 11 | 12 | i_INLINE_INS bool type_is_operator(const struct type *t); 13 | i_INLINE_INS struct type *typeop_to_type(struct type_operator *op); 14 | i_INLINE_INS enum typeop_type type_typeop_get(const struct type *t); 15 | i_INLINE_INS bool type_is_sumop(const struct type *t); 16 | i_INLINE_INS bool type_is_prodop(const struct type *t); 17 | i_INLINE_INS bool type_is_implop(const struct type *t); 18 | i_INLINE_INS bool type_is_sumtype(const struct type *t); 19 | 20 | const struct type *type_get_subtype(const struct type *t, unsigned int index) 21 | { 22 | if (t->category != TYPE_CATEGORY_OPERATOR) { 23 | return NULL; 24 | } 25 | if (index >= darray_size(t->operator.operands)) { 26 | return NULL; 27 | } 28 | return darray_item(t->operator.operands, index); 29 | } 30 | 31 | unsigned int type_get_subtypes_num(const struct type *t) 32 | { 33 | RF_ASSERT(t->category == TYPE_CATEGORY_OPERATOR, "Can't get operand of non-operator type"); 34 | return darray_size(t->operator.operands); 35 | } 36 | 37 | int type_is_direct_childof(const struct type *t, const struct type *maybe_parent) 38 | { 39 | if (maybe_parent->category != TYPE_CATEGORY_OPERATOR) { 40 | return false; 41 | } 42 | struct type **subt; 43 | int idx = 0; 44 | darray_foreach(subt, maybe_parent->operator.operands) { 45 | if (type_compare(*subt, t, TYPECMP_IDENTICAL)) { 46 | return idx; 47 | } 48 | ++idx; 49 | } 50 | return -1; 51 | } 52 | i_INLINE_INS int type_is_childof(const struct type *t, const struct type *maybe_parent); 53 | -------------------------------------------------------------------------------- /src/types/type_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | i_INLINE_INS bool ast_node_is_elementary_identifier(struct ast_node *n); 4 | -------------------------------------------------------------------------------- /src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | rf_target_and_test_sources(refu test_refu_helper PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common_strings.c" 2 | "${CMAKE_CURRENT_SOURCE_DIR}/data.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/string_set.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/traversal.c") 5 | -------------------------------------------------------------------------------- /src/utils/common_strings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const struct RFstring g_str_true = RF_STRING_STATIC_INIT("true"); 5 | const struct RFstring g_str_false = RF_STRING_STATIC_INIT("false"); 6 | const struct RFstring g_str_stdlib = RF_STRING_STATIC_INIT("stdlib"); 7 | const struct RFstring g_str_main = RF_STRING_STATIC_INIT("main"); 8 | const struct RFstring g_str_fnstart = RF_STRING_STATIC_INIT("function_start"); 9 | const struct RFstring g_str_string = RF_STRING_STATIC_INIT("string"); 10 | const struct RFstring g_str_defined = RF_STRING_STATIC_INIT("defined"); 11 | const struct RFstring g_str_foreign = RF_STRING_STATIC_INIT("foreign"); 12 | const struct RFstring g_str_elementary = RF_STRING_STATIC_INIT("elementary"); 13 | const struct RFstring g_str_composite = RF_STRING_STATIC_INIT("composite"); 14 | const struct RFstring g_str_array = RF_STRING_STATIC_INIT("array"); 15 | -------------------------------------------------------------------------------- /src/utils/data.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static i_THREAD__ struct RFstring *s_data_dir = NULL; 9 | 10 | const struct RFstring *rf_data_dir() 11 | { 12 | if (!s_data_dir) { 13 | RFS_PUSH(); 14 | const struct RFstring *home = rf_homedir(); 15 | RF_ASSERT_OR_EXIT(home, "Failed to get user's home directory"); 16 | s_data_dir = rf_string_createv(RFS_PF"/.refu", RFS_PA(home)); 17 | RF_ASSERT_OR_EXIT(s_data_dir, "Failed to allocate data dir string"); 18 | RFS_POP(); 19 | } 20 | return s_data_dir; 21 | } 22 | 23 | bool rf_data_dir_exists() 24 | { 25 | const struct RFstring *datadir = rf_data_dir(); 26 | if (!rf_system_file_exists(datadir)) { 27 | return rf_system_make_dir(datadir, RFP_IRWXU); 28 | } 29 | return true; 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/string_set.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | i_INLINE_INS const void *string_objset_key(const struct RFstring *s); 6 | 7 | size_t string_objset_hashfn(const struct RFstring *s) 8 | { 9 | return rf_hash_str_stable(s, 0); 10 | } 11 | 12 | bool string_objset_eqfn(const struct RFstring *s1, 13 | const struct RFstring *s2) 14 | { 15 | return rf_string_equal(s1, s2); 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/traversal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | i_INLINE_INS bool traversal_success(enum traversal_cb_res rc); 4 | i_INLINE_INS bool traversal_stop(enum traversal_cb_res rc); 5 | -------------------------------------------------------------------------------- /stdlib/io.rf: -------------------------------------------------------------------------------- 1 | module stdlib { 2 | 3 | foreign_import rf_stdlib_print_int64(i64), rf_stdlib_print_uint64(u64), rf_stdlib_print_string(string) 4 | 5 | fn print(a:i64 | b:u64 | s:string) 6 | a:i64 => rf_stdlib_print_int64(a) 7 | b:u64 => rf_stdlib_print_uint64(b) 8 | s:string => rf_stdlib_print_string(s) 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test_refu "") 2 | 3 | target_sources(test_refu PRIVATE 4 | "${CMAKE_CURRENT_SOURCE_DIR}/test_input_base.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/test_main.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_front.c") 8 | 9 | add_subdirectory(analyzer) 10 | add_subdirectory(end_to_end) 11 | add_subdirectory(lexer) 12 | add_subdirectory(parser) 13 | add_subdirectory(rir) 14 | add_subdirectory(types) 15 | 16 | # --- general stuff needed for tests 17 | target_compile_definitions(test_refu PUBLIC RF_UNIT_TESTS) 18 | include(FindPkgConfig) 19 | find_package(Check REQUIRED) 20 | pkg_check_modules(LIBCHECK REQUIRED check) # <-- this sets a bunch of variables 21 | target_link_libraries(test_refu PUBLIC check) 22 | target_link_libraries(test_refu PUBLIC ${LIBCHECK_LDFLAGS}) 23 | # --- stuff needed for refu tests 24 | target_link_libraries(test_refu PUBLIC test_refu_helper) 25 | rf_use_llvm(test_refu) 26 | 27 | target_compile_definitions(test_refu PUBLIC "CLIB_TEST_HELPERS=\"${CMAKE_CURRENT_SOURCE_DIR}/../rfbase/test/test_helpers.h\"") 28 | target_include_directories(test_refu PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 29 | -------------------------------------------------------------------------------- /test/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | # curl 4 | # Download stage0, see src/bootstrap/bootstrap.py 5 | # g++ 6 | # Compile LLVM binding in src/rustllvm 7 | # git 8 | # Get commit hash and commit date in version string 9 | # make 10 | # Run build scripts in mk 11 | # libedit-dev zlib1g-dev 12 | # LLVM dependencies as packaged in Ubuntu 13 | # (They are optional, but Ubuntu package enables them) 14 | # llvm-3.7-dev (installed by llvm-3.7-tools) 15 | # LLVM 16 | # llvm-3.7-tools 17 | # FileCheck is used to run tests in src/test/codegen 18 | 19 | RUN apt-get update && apt-get -y install \ 20 | curl g++ git make pkg-config \ 21 | cmake gperf check lcov ruby \ 22 | libedit-dev zlib1g-dev \ 23 | valgrind llvm-3.7-tools 24 | 25 | RUN gem install coveralls-lcov 26 | 27 | RUN mkdir /build 28 | WORKDIR /build 29 | -------------------------------------------------------------------------------- /test/analyzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/test_modules.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/test_symbol_table.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_arr.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_conversion.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_forexpr.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_functions.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_matchexpr.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck_operators.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_analyzer.c") 12 | -------------------------------------------------------------------------------- /test/end_to_end/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_end_to_end.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/test_end_to_end_basic.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/test_end_to_end_modules.c") 5 | -------------------------------------------------------------------------------- /test/end_to_end/test_end_to_end_modules.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "testsupport_end_to_end.h" 10 | 11 | #include CLIB_TEST_HELPERS 12 | 13 | START_TEST (test_smoke_module_inclusion) { 14 | struct test_input_pair inputs[] = { 15 | TEST_DECL_SRC( 16 | "main.rf", 17 | "import other\n" 18 | "fn main()->u32{return 42}" 19 | ), 20 | TEST_DECL_SRC( 21 | "other.rf", 22 | 23 | "module other {\n" 24 | "}" 25 | ) 26 | }; 27 | ck_end_to_end_run(inputs, 42); 28 | } END_TEST 29 | 30 | Suite *end_to_end_module_suite_create(void) 31 | { 32 | Suite *s = suite_create("end_to_end_module"); 33 | 34 | TCase *st_basic = tcase_create("end_to_end_module_simple"); 35 | tcase_add_checked_fixture(st_basic, 36 | setup_end_to_end_tests, 37 | teardown_end_to_end_tests); 38 | tcase_add_test(st_basic, test_smoke_module_inclusion); 39 | 40 | suite_add_tcase(s, st_basic); 41 | 42 | return s; 43 | } 44 | -------------------------------------------------------------------------------- /test/lexer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/test_lexer.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_lexer.c") 4 | -------------------------------------------------------------------------------- /test/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_block.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_function.c" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_generics.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_ifexpr.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_forexpr.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_matchexpr.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_misc.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_modules.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_operators.c" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_typeclass.c" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parser_typedesc.c" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_parser.c") 14 | -------------------------------------------------------------------------------- /test/rir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(creation) 2 | 3 | target_sources(test_refu PRIVATE 4 | "${CMAKE_CURRENT_SOURCE_DIR}/test_finalized_ast.c" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/test_ownership.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/test_parsing_rir.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/test_rir_end_to_end.c" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/test_rir_misc.c" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_rir.c" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/testsupport_rir_compare.c") 11 | -------------------------------------------------------------------------------- /test/rir/creation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/test_create_simple.c") 3 | -------------------------------------------------------------------------------- /test/rir/creation/test_create_simple.c: -------------------------------------------------------------------------------- 1 | #include "../testsupport_rir.h" 2 | 3 | #include CLIB_TEST_HELPERS 4 | 5 | START_TEST (test_create_simple_fn) { 6 | 7 | static const struct RFstring s = RF_STRING_STATIC_INIT( 8 | "fn foo(a:u32) -> u64 {\n" 9 | "return 45 + a\n" 10 | "}" 11 | ); 12 | front_testdriver_new_ast_main_source(&s); 13 | ck_assert_createrir_ok(); 14 | 15 | } END_TEST 16 | 17 | Suite *rir_creation_simple_suite_create(void) 18 | { 19 | Suite *s = suite_create("rir_creation_simple"); 20 | 21 | TCase *tc1 = tcase_create("test_functions"); 22 | tcase_add_checked_fixture(tc1, 23 | setup_rir_tests_no_stdlib, 24 | teardown_rir_tests); 25 | tcase_add_test(tc1, test_create_simple_fn); 26 | 27 | 28 | suite_add_tcase(s, tc1); 29 | 30 | return s; 31 | } 32 | -------------------------------------------------------------------------------- /test/rir/test_finalized_ast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "testsupport_rir.h" 11 | 12 | #include CLIB_TEST_HELPERS 13 | 14 | START_TEST (test_finalized_function_arguments) { 15 | 16 | static const struct RFstring s = RF_STRING_STATIC_INIT( 17 | "fn foo(a:u32) -> u64 {\n" 18 | "return 45 + a\n" 19 | "}" 20 | "fn boo(a:u32, b:string, c:f64) -> u64 {\n" 21 | "return 45 + a\n" 22 | "}" 23 | "fn goo() -> u64 {\n" 24 | "return 45\n" 25 | "}" 26 | ); 27 | front_testdriver_new_ast_main_source(&s); 28 | ck_assert_typecheck_ok(); 29 | 30 | struct ast_node *fn1 = ast_node_get_child(front_testdriver_module()->node, 0); 31 | ck_assert_uint_eq(ast_fndecl_argsnum_get(ast_fnimpl_fndecl_get(fn1)), 1); 32 | struct ast_node *fn2 = ast_node_get_child(front_testdriver_module()->node, 1); 33 | ck_assert_uint_eq(ast_fndecl_argsnum_get(ast_fnimpl_fndecl_get(fn2)), 3); 34 | struct ast_node *fn3 = ast_node_get_child(front_testdriver_module()->node, 2); 35 | ck_assert_uint_eq(ast_fndecl_argsnum_get(ast_fnimpl_fndecl_get(fn3)), 0); 36 | 37 | } END_TEST 38 | 39 | Suite *rir_finalized_ast_suite_create(void) 40 | { 41 | Suite *s = suite_create("rir_finalized_ast"); 42 | 43 | TCase *finalized_ast = tcase_create("finalized_ast_nodes"); 44 | tcase_add_checked_fixture(finalized_ast, 45 | setup_rir_tests_no_stdlib, 46 | teardown_rir_tests); 47 | tcase_add_test(finalized_ast, test_finalized_function_arguments); 48 | 49 | suite_add_tcase(s, finalized_ast); 50 | 51 | return s; 52 | } 53 | -------------------------------------------------------------------------------- /test/rir/test_ownership.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "testsupport_rir.h" 11 | 12 | #include CLIB_TEST_HELPERS 13 | 14 | START_TEST (test_usage_1) { 15 | // TODO: This test is still in progress 16 | static const struct RFstring s = RF_STRING_STATIC_INIT( 17 | "type person {name:string, age:u32}\n" 18 | "fn puse(p:person)\n" 19 | "{\n" 20 | " print(p.name)\n" 21 | "}\n" 22 | "fn main() -> u32{\n" 23 | " p:person = person(\"Lef\", 29)\n" 24 | " puse(p)\n" 25 | " print(p.name)\n" 26 | " return 22\n" 27 | "}\n" 28 | ); 29 | front_testdriver_new_ast_main_source(&s); 30 | ck_assert_createrir_ok(); 31 | } END_TEST 32 | 33 | Suite *ownership_suite_create(void) 34 | { 35 | Suite *s = suite_create("ownership"); 36 | 37 | TCase *tc1 = tcase_create("ownership_usage"); 38 | tcase_add_checked_fixture(tc1, 39 | setup_rir_tests, 40 | teardown_rir_tests); 41 | tcase_add_test(tc1, test_usage_1); 42 | 43 | suite_add_tcase(s, tc1); 44 | 45 | return s; 46 | } 47 | -------------------------------------------------------------------------------- /test/rir/test_rir_end_to_end.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../end_to_end/testsupport_end_to_end.h" 7 | 8 | #include CLIB_TEST_HELPERS 9 | 10 | START_TEST (test_rir_end_to_end_simple_module1) { 11 | struct test_input_pair inputs[] = { 12 | TEST_DECL_SRC( 13 | "test_input_file.rir", 14 | 15 | "$gstr_3855993015 = global(string, \"false\")\n" 16 | "$gstr_3784272022 = global(string, \"foo\")\n" 17 | "$gstr_706834940 = global(string, \"true\")\n" 18 | "$internal_struct_4260204557 = uniondef(i64, u64, string)\n" 19 | "fndef(other_function; string*; u32)\n" 20 | "{\n" 21 | "%function_start\n" 22 | " $3 = convert(14, u32)\n" 23 | " write(u32*, $1, $3)\n" 24 | " branch(%function_end)\n" 25 | "%function_end\n" 26 | " $2 = read($1)\n" 27 | " return($2)\n" 28 | "}\n" 29 | "fndef(main; nil; u32)\n" 30 | "{\n" 31 | "%function_start\n" 32 | " $2 = call(other_function, foreign, $gstr_3784272022)\n" 33 | " write(u32*, $0, $2)\n" 34 | " branch(%function_end)\n" 35 | "%function_end\n" 36 | " $1 = read($0)\n" 37 | " return($1)\n" 38 | "}\n" 39 | ) 40 | }; 41 | ck_end_to_end_run(inputs, 14, NULL, "--rir test_input_file.rir"); 42 | 43 | } END_TEST 44 | 45 | Suite *rir_end_to_end_suite_create(void) 46 | { 47 | Suite *s = suite_create("rir_end_to_end"); 48 | 49 | TCase *tc1 = tcase_create("simple_rir_module"); 50 | tcase_add_checked_fixture(tc1, 51 | setup_end_to_end_tests, 52 | teardown_end_to_end_tests); 53 | tcase_add_test(tc1, test_rir_end_to_end_simple_module1); 54 | 55 | suite_add_tcase(s, tc1); 56 | return s; 57 | } 58 | -------------------------------------------------------------------------------- /test/rir/testsupport_rir_compare.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TESTSUPPORT_RIR_COMPARE_H 2 | #define LFR_TESTSUPPORT_RIR_COMPARE_H 3 | 4 | struct rir_type; 5 | struct rir_expression; 6 | struct RFstring; 7 | 8 | #include 9 | 10 | bool ckr_compare_type( 11 | const struct rir_type *got, 12 | const struct rir_type *expect, 13 | const char *file, 14 | unsigned int line, 15 | const struct RFstring *intro 16 | ); 17 | 18 | bool ckr_compare_expression( 19 | struct rir_expression *got, 20 | struct rir_expression *expect, 21 | const char *file, 22 | unsigned int line, 23 | const struct RFstring *intro 24 | ); 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /test/testsupport.c: -------------------------------------------------------------------------------- 1 | #include "testsupport.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | void setup_base_tests() 8 | { 9 | ck_assert_msg(rf_init(LOG_TARGET_STDOUT, 10 | NULL, 11 | LOG_WARNING, 12 | RF_DEFAULT_TS_MBUFF_INITIAL_SIZE, 13 | RF_DEFAULT_TS_SBUFF_INITIAL_SIZE), 14 | "Failed to initialize refu library"); 15 | } 16 | void teardown_base_tests() 17 | { 18 | rf_deinit(); 19 | } 20 | -------------------------------------------------------------------------------- /test/testsupport.h: -------------------------------------------------------------------------------- 1 | #ifndef LFR_TESTSUPPORT_H 2 | #define LFR_TESTSUPPORT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void setup_base_tests(); 9 | void teardown_base_tests(); 10 | 11 | /** 12 | * Abort test at a specific location with a specific message 13 | */ 14 | #define ck_abort_at(...) \ 15 | do { \ 16 | RFS_PUSH(); \ 17 | RF_SELECT_FUNC_IF_NARGGT(CK_ABORT_AT_WITHVARGS, 4, __VA_ARGS__); \ 18 | RFS_POP(); \ 19 | } while (0) 20 | 21 | #define CK_ABORT_LESTR ".\nAt %s:%u\n\t" 22 | #define CK_ABORT_AT_WITHVARGS1(file_, line_, msg_intro_, msg_, ...) \ 23 | ck_abort_msg( \ 24 | msg_intro_ CK_ABORT_LESTR msg_, \ 25 | file_, \ 26 | line_, \ 27 | __VA_ARGS__ \ 28 | ) 29 | 30 | #define CK_ABORT_AT_WITHVARGS0(file_, line_, msg_intro_, msg_) \ 31 | ck_abort_msg( \ 32 | msg_intro_ CK_ABORT_LESTR msg_, \ 33 | file_, \ 34 | line_ \ 35 | ) 36 | 37 | 38 | // make a copy of a static array and put the copy in the darray. 39 | // We are doing this only if the darray takes ownership of the copy and will 40 | // free it later. If we just did a raw copy, there would be an attempt to free 41 | // a static array. 42 | #define testsupport_arr_with_size_to_darray(darr_, arr_, size_, type_) \ 43 | do { \ 44 | type_ *newarr = malloc(size_); \ 45 | if (!newarr) { \ 46 | ck_abort_msg("Failed to allocate an array"); \ 47 | } \ 48 | memcpy(newarr, arr_, size_); \ 49 | darray_raw_copy( \ 50 | darr_, \ 51 | newarr, \ 52 | size_ / sizeof(type_) \ 53 | ); \ 54 | } while (0) 55 | 56 | #define testsupport_arr_to_darray(darr_, arr_, type_) \ 57 | testsupport_arr_with_size_to_darray(darr_, arr_, sizeof(arr_), type_) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /test/types/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(test_refu PRIVATE 2 | "${CMAKE_CURRENT_SOURCE_DIR}/test_types.c" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/test_typeset.c") 4 | --------------------------------------------------------------------------------