├── .clang-format ├── .gitattributes ├── .github └── workflows │ ├── build-release.yml │ ├── build.yml │ ├── build_with_asan.yml │ ├── build_with_cov.yml │ └── cppcheck.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── benchmark_common.cpp ├── benchmark_cpp.cpp ├── benchmark_fakelua.cpp ├── benchmark_lua.cpp ├── lua │ └── bench_algo │ │ └── fibonacci.lua └── main.cpp ├── cmake └── CPM.cmake ├── cmd ├── CMakeLists.txt └── main.cpp ├── include └── fakelua.h ├── src ├── CMakeLists.txt ├── README.md ├── compile │ ├── README.md │ ├── bison │ │ ├── build.sh │ │ ├── location.hh │ │ ├── parser.cpp │ │ ├── parser.h │ │ └── parser.y │ ├── compile_common.h │ ├── compiler.cpp │ ├── compiler.h │ ├── flex │ │ ├── build.sh │ │ ├── scanner.cpp │ │ └── scanner.l │ ├── myflexer.cpp │ ├── myflexer.h │ ├── syntax_tree.cpp │ └── syntax_tree.h ├── fakelua │ └── fakelua.cpp ├── jit │ ├── gcc_jit.cpp │ ├── gcc_jit.h │ ├── gcc_jit_handle.cpp │ ├── gcc_jit_handle.h │ ├── preprocessor.cpp │ ├── preprocessor.h │ ├── vm.cpp │ ├── vm.h │ └── vm_function.h ├── platform │ └── FlexLexer.h ├── state │ ├── state.cpp │ ├── state.h │ ├── var_pool.cpp │ ├── var_pool.h │ ├── var_string_heap.cpp │ ├── var_string_heap.h │ ├── var_table_heap.cpp │ └── var_table_heap.h ├── util │ ├── call_helper.h │ ├── common.h │ ├── const_define.h │ ├── debug.cpp │ ├── debug.h │ ├── exception.cpp │ ├── exception.h │ ├── file_util.cpp │ ├── file_util.h │ ├── hash_func.h │ ├── logging.cpp │ ├── logging.h │ ├── macro.h │ ├── string_util.cpp │ └── string_util.h └── var │ ├── var.cpp │ ├── var.h │ ├── var_string.cpp │ ├── var_string.h │ ├── var_table.cpp │ ├── var_table.h │ └── var_type.h └── test ├── CMakeLists.txt ├── lua ├── algo │ └── fibonacci.lua ├── exception │ ├── test_binop_plus_error.lua │ ├── test_break_error.lua │ ├── test_col_func_not_find_error.lua │ ├── test_col_func_param_error.lua │ ├── test_col_func_table_error.lua │ ├── test_col_func_type_error.lua │ ├── test_compile_fail.lua │ ├── test_const_binop_bitand_error.lua │ ├── test_const_binop_bitor_error.lua │ ├── test_const_binop_double_slash_error.lua │ ├── test_const_binop_left_shift_error.lua │ ├── test_const_binop_less_equal_error.lua │ ├── test_const_binop_less_error.lua │ ├── test_const_binop_minus_error.lua │ ├── test_const_binop_mod_error.lua │ ├── test_const_binop_more_equal_error.lua │ ├── test_const_binop_more_error.lua │ ├── test_const_binop_plus_error.lua │ ├── test_const_binop_pow_error.lua │ ├── test_const_binop_right_shift_error.lua │ ├── test_const_binop_slash_error.lua │ ├── test_const_binop_star_error.lua │ ├── test_const_binop_xor_error.lua │ ├── test_const_define_duplicate.lua │ ├── test_const_define_func_param_duplicate.lua │ ├── test_const_define_no_match.lua │ ├── test_const_define_no_value.lua │ ├── test_const_define_variadic.lua │ ├── test_const_func_call_error.lua │ ├── test_const_unop_bitnot_error.lua │ ├── test_const_unop_len_error.lua │ ├── test_for_in_exp_error.lua │ ├── test_for_in_explist_error.lua │ ├── test_for_in_func_args_error.lua │ ├── test_for_in_func_error.lua │ ├── test_for_in_namelist_error.lua │ ├── test_for_in_pairs_error.lua │ ├── test_for_in_prefix_error.lua │ ├── test_for_in_prefix_func_error.lua │ ├── test_function_call_exception.lua │ ├── test_function_param_duplicate.lua │ ├── test_function_param_local_duplicate.lua │ ├── test_global_duplicate_lvalue_error.lua │ ├── test_label_exception.lua │ ├── test_local_define_duplicate.lua │ ├── test_no_define_lvalue_error.lua │ ├── test_return_type_error.lua │ ├── test_stmt_support_error.lua │ ├── test_table_get_error.lua │ ├── test_table_loop_error.lua │ ├── test_table_set_error.lua │ ├── test_unop_minus_error.lua │ └── test_variadic_function_call_exception.lua ├── jit │ ├── test_assign.lua │ ├── test_assign_not_match.lua │ ├── test_assign_simple_var.lua │ ├── test_assign_table_var.lua │ ├── test_assign_variadic.lua │ ├── test_assign_variadic_no_match.lua │ ├── test_binop_and.lua │ ├── test_binop_and_bool.lua │ ├── test_binop_and_or.lua │ ├── test_binop_bitand.lua │ ├── test_binop_bitor.lua │ ├── test_binop_concat.lua │ ├── test_binop_double_slash.lua │ ├── test_binop_equal.lua │ ├── test_binop_left_shift.lua │ ├── test_binop_less.lua │ ├── test_binop_less_equal.lua │ ├── test_binop_minus.lua │ ├── test_binop_mod.lua │ ├── test_binop_more.lua │ ├── test_binop_more_equal.lua │ ├── test_binop_not_equal.lua │ ├── test_binop_or.lua │ ├── test_binop_plus.lua │ ├── test_binop_pow.lua │ ├── test_binop_right_shift.lua │ ├── test_binop_slash.lua │ ├── test_binop_star.lua │ ├── test_binop_xor.lua │ ├── test_const_binop_and.lua │ ├── test_const_binop_bitand.lua │ ├── test_const_binop_bitor.lua │ ├── test_const_binop_concat.lua │ ├── test_const_binop_double_slash.lua │ ├── test_const_binop_equal.lua │ ├── test_const_binop_left_shift.lua │ ├── test_const_binop_less.lua │ ├── test_const_binop_less_equal.lua │ ├── test_const_binop_minus.lua │ ├── test_const_binop_mod.lua │ ├── test_const_binop_more.lua │ ├── test_const_binop_more_equal.lua │ ├── test_const_binop_not_equal.lua │ ├── test_const_binop_or.lua │ ├── test_const_binop_plus.lua │ ├── test_const_binop_pow.lua │ ├── test_const_binop_right_shift.lua │ ├── test_const_binop_slash.lua │ ├── test_const_binop_star.lua │ ├── test_const_binop_xor.lua │ ├── test_const_define.lua │ ├── test_const_define_simple_var.lua │ ├── test_const_nested_table.lua │ ├── test_const_table.lua │ ├── test_const_table_define.lua │ ├── test_const_unop_bitnot.lua │ ├── test_const_unop_len.lua │ ├── test_const_unop_minus.lua │ ├── test_const_unop_not.lua │ ├── test_do_block.lua │ ├── test_empty_file.lua │ ├── test_empty_func.lua │ ├── test_empty_func_call.lua │ ├── test_empty_func_no_return.lua │ ├── test_empty_func_with_params.lua │ ├── test_empty_local_func.lua │ ├── test_empty_return.lua │ ├── test_for_in.lua │ ├── test_for_in_break.lua │ ├── test_for_in_double.lua │ ├── test_for_in_if_return.lua │ ├── test_for_in_just_break.lua │ ├── test_for_in_return.lua │ ├── test_for_in_return_fallback.lua │ ├── test_for_loop.lua │ ├── test_for_loop_break.lua │ ├── test_for_loop_default.lua │ ├── test_for_loop_double.lua │ ├── test_for_loop_if_return.lua │ ├── test_for_loop_just_break.lua │ ├── test_for_loop_return.lua │ ├── test_global_func_call.lua │ ├── test_if.lua │ ├── test_if_else.lua │ ├── test_if_elseif.lua │ ├── test_if_elseif_normal.lua │ ├── test_if_elseif_return.lua │ ├── test_if_simple.lua │ ├── test_local_define.lua │ ├── test_local_define_with_value.lua │ ├── test_local_func_call.lua │ ├── test_local_func_call_string.lua │ ├── test_local_func_call_table_construct.lua │ ├── test_local_nested_table.lua │ ├── test_local_table.lua │ ├── test_local_table_with_variadic.lua │ ├── test_local_table_with_variadic_no_end.lua │ ├── test_local_table_with_variadic_no_end_replace.lua │ ├── test_multi_col_name_func.lua │ ├── test_multi_const_define.lua │ ├── test_multi_name_func.lua │ ├── test_multi_return.lua │ ├── test_multi_return_call.lua │ ├── test_multi_return_call_ex.lua │ ├── test_multi_return_multi.lua │ ├── test_multi_return_multi_ex.lua │ ├── test_multi_return_sub.lua │ ├── test_repeat.lua │ ├── test_repeat_break.lua │ ├── test_repeat_double.lua │ ├── test_repeat_if_return.lua │ ├── test_repeat_just_break.lua │ ├── test_repeat_return.lua │ ├── test_table_get_set.lua │ ├── test_table_var_func_call.lua │ ├── test_unop_bitnot.lua │ ├── test_unop_len.lua │ ├── test_unop_minus.lua │ ├── test_unop_not.lua │ ├── test_var_func_call.lua │ ├── test_variadic_func.lua │ ├── test_variadic_func_with_params.lua │ ├── test_while.lua │ ├── test_while_break.lua │ ├── test_while_double.lua │ ├── test_while_if_return.lua │ ├── test_while_just_break.lua │ └── test_while_return.lua └── syntax │ ├── test_assign.lua │ ├── test_assign_simple.lua │ ├── test_binop.lua │ ├── test_binop_order1.lua │ ├── test_binop_order2.lua │ ├── test_binop_order3.lua │ ├── test_binop_order4.lua │ ├── test_binop_order5.lua │ ├── test_binop_order6.lua │ ├── test_break.lua │ ├── test_constructor.lua │ ├── test_continue.lua │ ├── test_do_end.lua │ ├── test_empty.lua │ ├── test_for_in.lua │ ├── test_for_num.lua │ ├── test_function.lua │ ├── test_function_call.lua │ ├── test_function_call_args.lua │ ├── test_function_exp.lua │ ├── test_if.lua │ ├── test_label.lua │ ├── test_number.lua │ ├── test_repeat.lua │ ├── test_string.lua │ ├── test_var.lua │ ├── test_var_attr.lua │ └── test_while.lua ├── main.cpp ├── test_algo.cpp ├── test_common.cpp ├── test_exception.cpp ├── test_ini.cpp ├── test_jitter.cpp ├── test_syntax_tree.cpp └── test_var.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: None 6 | AlignOperands: Align 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: false 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 140 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: None 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf -------------------------------------------------------------------------------- /.github/workflows/build-release.yml: -------------------------------------------------------------------------------- 1 | name: BuildRelease 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-24.04 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | 16 | - name: Setup GCC 17 | uses: pkgxdev/setup@v1 18 | with: 19 | +: gcc@13 20 | 21 | - name: Setup Lua 22 | run: | 23 | wget https://www.lua.org/ftp/lua-5.4.7.tar.gz 24 | tar -xf lua-5.4.7.tar.gz 25 | cd lua-5.4.7 26 | make linux 27 | sudo make install 28 | cd .. 29 | 30 | - name: Prepare 31 | run: | 32 | sudo apt-get -y install libgccjit-13-dev 33 | dpkg -L libgccjit-13-dev 34 | sudo mv /usr/lib/gcc/x86_64-linux-gnu/13/include/libgccjit* /usr/include/ 35 | sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/13/libgccjit.so /usr/lib/libgccjit.so 36 | 37 | - name: Build 38 | run: | 39 | set -x 40 | rm build -rf 41 | mkdir build 42 | cd build 43 | cmake -DCMAKE_BUILD_TYPE=Release .. 44 | make -j8 45 | ctest -V 46 | ./bin/bench_mark 47 | ./bin/flua 48 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-24.04 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | 16 | - name: Setup GCC 17 | uses: pkgxdev/setup@v1 18 | with: 19 | +: gcc@13 20 | 21 | - name: Setup Lua 22 | run: | 23 | wget https://www.lua.org/ftp/lua-5.4.7.tar.gz 24 | tar -xf lua-5.4.7.tar.gz 25 | cd lua-5.4.7 26 | make linux 27 | sudo make install 28 | cd .. 29 | 30 | - name: Prepare 31 | run: | 32 | sudo apt-get -y install libgccjit-13-dev 33 | dpkg -L libgccjit-13-dev 34 | sudo mv /usr/lib/gcc/x86_64-linux-gnu/13/include/libgccjit* /usr/include/ 35 | sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/13/libgccjit.so /usr/lib/libgccjit.so 36 | 37 | - name: Build 38 | run: | 39 | set -x 40 | rm build -rf 41 | mkdir build 42 | cd build 43 | cmake .. 44 | make -j8 45 | ctest -V 46 | ./bin/bench_mark 47 | ./bin/flua 48 | -------------------------------------------------------------------------------- /.github/workflows/build_with_asan.yml: -------------------------------------------------------------------------------- 1 | name: BuildWithASAN 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | 17 | - name: Setup GCC 18 | uses: pkgxdev/setup@v1 19 | with: 20 | +: gcc@13 21 | 22 | - name: Setup Lua 23 | run: | 24 | wget https://www.lua.org/ftp/lua-5.4.7.tar.gz 25 | tar -xf lua-5.4.7.tar.gz 26 | cd lua-5.4.7 27 | make linux 28 | sudo make install 29 | cd .. 30 | 31 | - name: Prepare 32 | run: | 33 | sudo apt-get -y install libgccjit-13-dev 34 | dpkg -L libgccjit-13-dev 35 | sudo mv /usr/lib/gcc/x86_64-linux-gnu/13/include/libgccjit* /usr/include/ 36 | sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/13/libgccjit.so /usr/lib/libgccjit.so 37 | 38 | - name: Build with asan 39 | run: | 40 | set -x 41 | rm build -rf 42 | mkdir build 43 | cd build 44 | export ASAN_OPTIONS=detect_leaks=0 45 | cmake -DUSE_ASAN=ON .. 46 | make -j8 47 | ctest -V 48 | ./bin/bench_mark 49 | ./bin/flua 50 | -------------------------------------------------------------------------------- /.github/workflows/build_with_cov.yml: -------------------------------------------------------------------------------- 1 | name: BuildWithCOV 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | 17 | - name: Setup GCC 18 | uses: pkgxdev/setup@v1 19 | with: 20 | +: gcc@13 21 | 22 | - name: Setup Lua 23 | run: | 24 | wget https://www.lua.org/ftp/lua-5.4.7.tar.gz 25 | tar -xf lua-5.4.7.tar.gz 26 | cd lua-5.4.7 27 | make linux 28 | sudo make install 29 | cd .. 30 | 31 | - name: Prepare 32 | run: | 33 | sudo apt-get -y install libgccjit-13-dev 34 | dpkg -L libgccjit-13-dev 35 | sudo mv /usr/lib/gcc/x86_64-linux-gnu/13/include/libgccjit* /usr/include/ 36 | sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/13/libgccjit.so /usr/lib/libgccjit.so 37 | wget https://github.com/linux-test-project/lcov/releases/download/v2.0/lcov-2.0.tar.gz 38 | tar -xf lcov-2.0.tar.gz 39 | cd lcov-2.0/ 40 | sudo make install 41 | yes|sudo perl -MCPAN -e 'install Capture::Tiny' 42 | sudo apt-get install libdatetime-perl -y 43 | sudo rm /usr/bin/lcov -f 44 | sudo ln -s /usr/local/bin/lcov /usr/bin/lcov 45 | lcov --version 46 | cd .. 47 | 48 | - name: Build with cov 49 | run: | 50 | set -x 51 | rm build -rf 52 | mkdir build 53 | cd build 54 | cmake -DUSE_COV=ON .. 55 | make -j8 56 | ctest -V 57 | ./bin/bench_mark 58 | ./bin/flua 59 | echo "function main() return 0 end" > test.lua 60 | ./bin/flua test.lua 61 | lcov --directory ./ --capture --output-file coverage.info --ignore-errors source --ignore-errors mismatch 62 | ls -l coverage.info 63 | lcov --list coverage.info 64 | bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV }} -f coverage.info || echo "Codecov did not collect coverage reports" 65 | 66 | -------------------------------------------------------------------------------- /.github/workflows/cppcheck.yml: -------------------------------------------------------------------------------- 1 | name: CppCheck 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | 17 | - name: Setup GCC 18 | uses: pkgxdev/setup@v1 19 | with: 20 | +: gcc@13 21 | 22 | - name: Prepare 23 | run: | 24 | sudo apt-get -y install libgccjit-13-dev 25 | dpkg -L libgccjit-13-dev 26 | sudo mv /usr/lib/gcc/x86_64-linux-gnu/13/include/libgccjit* /usr/include/ 27 | sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/13/libgccjit.so /usr/lib/libgccjit.so 28 | 29 | - name: Build 30 | run: | 31 | set -x 32 | wget https://github.com/danmar/cppcheck/archive/refs/tags/2.12.1.tar.gz 33 | tar -xf 2.12.1.tar.gz 34 | cd cppcheck-2.12.1 35 | mkdir build 36 | cd build 37 | cmake .. 38 | make -j8 39 | sudo make install 40 | cd .. 41 | cd .. 42 | cppcheck --version 43 | FILES=`find src/ cmd/ -type f -name "*.cpp" -o -name "*.h"|grep -v parser|grep -v scanner` 44 | cppcheck --language=c++ --check-level=exhaustive --max-ctu-depth=64 -j8 $FILES 2> err.txt 45 | cat err.txt 46 | if [[ -s err.txt ]] 47 | then 48 | exit 1 49 | fi -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .idea 35 | build 36 | cmake-build-debug 37 | cmake_install.cmake 38 | CMakeFiles 39 | CTestTestfile.cmake 40 | Makefile 41 | googletest 42 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | project(fakelua CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 23) 6 | 7 | # add dependencies 8 | include(cmake/CPM.cmake) 9 | 10 | # place binaries and libraries according to GNU standards 11 | include(GNUInstallDirs) 12 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) 13 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) 14 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) 15 | 16 | set(ENV{FAKELUA_HOME} "${CMAKE_CURRENT_SOURCE_DIR}/") 17 | 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-local-typedefs -Wno-unused-function -DNDEBUG -g3 -ggdb3 -fPIC") 19 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -DNDEBUG -g3 -ggdb3 -fPIC") 20 | 21 | option(USE_ASAN "use asan" OFF) 22 | if (USE_ASAN) 23 | message("build with asan") 24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") 25 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") 26 | endif () 27 | 28 | option(USE_COV "use cov" OFF) 29 | if (USE_COV) 30 | message("build with cov") 31 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fprofile-update=atomic") 32 | endif () 33 | 34 | IF (WIN32) 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") 36 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") 37 | ELSE () 38 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") 39 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") 40 | ENDIF () 41 | 42 | find_program(CCACHE_PROGRAM ccache) 43 | if (CCACHE_PROGRAM) 44 | message("build with ccache") 45 | set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 46 | endif () 47 | 48 | add_subdirectory(src) 49 | add_subdirectory(cmd) 50 | 51 | enable_testing() 52 | add_subdirectory(test) 53 | add_subdirectory(benchmark) 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 zhao xin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FakeLua(Work in process) 2 | [](https://github.com/esrrhs/fakelua) 3 | [](https://github.com/esrrhs/fakelua) 4 | [](https://github.com/esrrhs/fakelua/actions) 5 | [![codecov](https://codecov.io/gh/esrrhs/fakelua/graph/badge.svg?token=9ZCUH1Q632)](https://codecov.io/gh/esrrhs/fakelua) 6 | 7 | FakeLua is a subset of Lua that compiles code into native machine code at runtime using Just-In-Time (JIT) compilation, providing a streamlined language structure and improved performance. 8 | 9 | # Features: 10 | * Compiles with C++23 11 | * Builds on Linux and MinGW 12 | * Supports Lua 5.4 syntax 13 | * Uses Flex and Bison for lexing and parsing 14 | * Compiles to native code using GCC JIT 15 | * Supports GDB for debugging Lua source code 16 | 17 | # Differences from Lua: 18 | * No global variables, only global constants 19 | * No garbage collection (GC); uses a memory pool instead 20 | * No coroutines, threads, userdata, or metatables 21 | * Tables are exclusively hash tables, not array tables 22 | * String concatenation supports all data types 23 | * No closures, as they are slow and complex to implement 24 | 25 | 26 | # Directory structure 27 | * [include](./include) header file 28 | * [src](./src) source code 29 | * [test](./test) test code 30 | * [benchmark](./benchmark) benchmark code 31 | * [cmd](./cmd) command line tool 32 | * [cmake](./cmake) cmake toolchain 33 | 34 | # Build 35 | ### Linux 36 | * Dependent: install gcc-13 with jit, cmake, flex, bison. install Lua for test. 37 | * Build: 38 | ```shell 39 | mkdir build 40 | cd build 41 | cmake .. 42 | make 43 | ``` 44 | 45 | ### Mingw 46 | * Dependent: install [MSYS2](https://www.msys2.org). install [mingw-w64-x86_64-libgccjit](https://packages.msys2.org/package/mingw-w64-x86_64-libgccjit), [mingw-w64-x86_64-lua](https://packages.msys2.org/package/mingw-w64-x86_64-lua). install CLion. 47 | * open project with CLion, set mingw toolchains. and build. 48 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | project(benchmark) 4 | 5 | #add benchmark 6 | CPMAddPackage( 7 | NAME benchmark 8 | GITHUB_REPOSITORY google/benchmark 9 | GIT_TAG v1.9.4 10 | OPTIONS 11 | "BENCHMARK_ENABLE_TESTING Off" 12 | "BENCHMARK_ENABLE_GTEST_TESTS Off" 13 | "BENCHMARK_ENABLE_ASSEMBLY_TESTS Off" 14 | "BENCHMARK_ENABLE_EXCEPTIONS Off" 15 | "BENCHMARK_ENABLE_INSTALL Off" 16 | "BENCHMARK_ENABLE_LTO Off" 17 | "BENCHMARK_ENABLE_NO_EXCEPTIONS Off" 18 | "BENCHMARK_ENABLE_TESTING Off" 19 | "BENCHMARK_ENABLE_TESTING Off" 20 | "BENCHMARK_USE_LIBCXX Off" 21 | "BENCHMARK_USE_LIBCXXABI Off" 22 | "BENCHMARK_USE_SANITIZER Off" 23 | "BENCHMARK_USE_VALGRIND Off" 24 | "BENCHMARK_DOWNLOAD_DEPENDENCIES Off" 25 | "BENCHMARK_ENABLE_GTEST_TESTS Off" 26 | "BENCHMARK_ENABLE_EXCEPTIONS Off" 27 | "BENCHMARK_ENABLE_INSTALL Off" 28 | "BENCHMARK_ENABLE_LTO Off" 29 | "BENCHMARK_ENABLE_NO_EXCEPTIONS Off" 30 | "BENCHMARK_ENABLE_TESTING Off" 31 | "BENCHMARK_ENABLE_TESTING Off" 32 | "BENCHMARK_USE_LIBCXX Off" 33 | "BENCHMARK_USE_LIBCXXABI Off" 34 | "BENCHMARK_USE_SANITIZER Off" 35 | "BENCHMARK_USE_VALGRIND Off" 36 | "BENCHMARK_DOWNLOAD_DEPENDENCIES Off" 37 | ) 38 | 39 | include_directories(${magic_enum_SOURCE_DIR}/include/magic_enum) 40 | 41 | aux_source_directory(./ BENCHMARK_SRC_LIST) 42 | include_directories(./) 43 | include_directories(../include) 44 | include_directories(../src) 45 | include_directories(../src/platform) 46 | 47 | IF (WIN32) 48 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-all-symbols") 49 | ELSE () 50 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-E") 51 | ENDIF () 52 | 53 | add_executable(bench_mark ${BENCHMARK_SRC_LIST}) 54 | 55 | target_link_libraries(bench_mark PRIVATE fakelua benchmark gccjit lua) 56 | 57 | add_custom_command( 58 | TARGET bench_mark 59 | POST_BUILD 60 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/lua/ ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/ 61 | ) 62 | -------------------------------------------------------------------------------- /benchmark/benchmark_common.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | 5 | using namespace fakelua; 6 | -------------------------------------------------------------------------------- /benchmark/benchmark_cpp.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | 5 | using namespace fakelua; 6 | 7 | static int fibonacci(int n) { 8 | if (n <= 1) { 9 | return n; 10 | } else { 11 | return fibonacci(n - 1) + fibonacci(n - 2); 12 | } 13 | } 14 | 15 | static void BM_cpp_fibonacci(benchmark::State &state) { 16 | for (auto _: state) { 17 | int ret = 0; 18 | ret = fibonacci(30); 19 | if (ret != 832040) { 20 | throw std::runtime_error("C++ Fibonacci result is incorrect: " + std::to_string(ret)); 21 | } 22 | } 23 | } 24 | 25 | BENCHMARK(BM_cpp_fibonacci); 26 | -------------------------------------------------------------------------------- /benchmark/benchmark_fakelua.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | 5 | using namespace fakelua; 6 | 7 | static void load_fakelua_file(fakelua_state_ptr L, const std::string &file) { 8 | try { 9 | L->compile_file(file, {.debug_mode = false}); 10 | } catch (...) { 11 | L->compile_file("bin/" + file, {.debug_mode = false}); 12 | } 13 | } 14 | 15 | struct FakeLuaGlobalIni { 16 | FakeLuaGlobalIni() { 17 | L = fakelua_newstate(); 18 | load_fakelua_file(L, "bench_algo/fibonacci.lua"); 19 | } 20 | fakelua_state_ptr L; 21 | }; 22 | 23 | static FakeLuaGlobalIni fakelua_global_ini; 24 | 25 | static void BM_fakelua_fibonacci(benchmark::State &state) { 26 | for (auto _: state) { 27 | int ret = 0; 28 | fakelua_global_ini.L->call("main", std::tie(ret), 30); 29 | if (ret != 832040) { 30 | throw std::runtime_error("fakelua Fibonacci result is incorrect: " + std::to_string(ret)); 31 | } 32 | } 33 | } 34 | 35 | BENCHMARK(BM_fakelua_fibonacci); 36 | -------------------------------------------------------------------------------- /benchmark/benchmark_lua.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | #include // Lua C API 5 | 6 | using namespace fakelua; 7 | 8 | static void load_lua_file(lua_State *L, const std::string &file) { 9 | if (luaL_dofile(L, file.c_str()) != LUA_OK) { 10 | luaL_dofile(L, ("bin/" + file).c_str()); 11 | } 12 | } 13 | 14 | template 15 | void push_to_lua(lua_State *L, T value); 16 | 17 | template<> 18 | void push_to_lua(lua_State *L, int value) { 19 | lua_pushinteger(L, value); 20 | } 21 | 22 | template 23 | void push_args(lua_State *L, T first, Args... args) { 24 | push_to_lua(L, first); 25 | push_args(L, args...); 26 | } 27 | 28 | void push_args(lua_State *L) { 29 | } 30 | 31 | template 32 | bool call_lua_func(lua_State *L, const std::string &funcName, int &ret, Args... args) { 33 | int top = lua_gettop(L); // 获取栈顶位置 34 | lua_getglobal(L, funcName.c_str());// 获取函数 35 | DEBUG_ASSERT(lua_isfunction(L, -1)); 36 | 37 | push_args(L, args...); 38 | 39 | constexpr int nargs = sizeof...(Args); 40 | int code = lua_pcall(L, nargs, 1, 0); 41 | DEBUG_ASSERT(code == LUA_OK); 42 | 43 | ret = lua_tointeger(L, -1); 44 | lua_settop(L, top); 45 | return true; 46 | } 47 | 48 | struct LuaGlobalIni { 49 | LuaGlobalIni() { 50 | L = luaL_newstate(); 51 | luaL_openlibs(L); 52 | load_lua_file(L, "bench_algo/fibonacci.lua"); 53 | } 54 | ~LuaGlobalIni() { 55 | if (L) { 56 | lua_close(L); 57 | } 58 | } 59 | lua_State *L = nullptr; 60 | }; 61 | 62 | static LuaGlobalIni lua_global_ini; 63 | 64 | static void BM_lua_fibonacci(benchmark::State &state) { 65 | for (auto _: state) { 66 | int ret = 0; 67 | call_lua_func(lua_global_ini.L, "main", ret, 30); 68 | if (ret != 832040) { 69 | throw std::runtime_error("Lua Fibonacci result is incorrect: " + std::to_string(ret)); 70 | } 71 | } 72 | } 73 | 74 | BENCHMARK(BM_lua_fibonacci); 75 | -------------------------------------------------------------------------------- /benchmark/lua/bench_algo/fibonacci.lua: -------------------------------------------------------------------------------- 1 | local function fibonacci(n) 2 | if n <= 1 then 3 | return n 4 | else 5 | return fibonacci(n - 1) + fibonacci(n - 2) 6 | end 7 | end 8 | 9 | function main(arg) 10 | return fibonacci(arg) 11 | end 12 | -------------------------------------------------------------------------------- /benchmark/main.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | 3 | BENCHMARK_MAIN(); 4 | -------------------------------------------------------------------------------- /cmake/CPM.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: MIT 2 | # 3 | # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors 4 | 5 | set(CPM_DOWNLOAD_VERSION 0.38.7) 6 | set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5") 7 | 8 | if(CPM_SOURCE_CACHE) 9 | set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 10 | elseif(DEFINED ENV{CPM_SOURCE_CACHE}) 11 | set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 12 | else() 13 | set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 14 | endif() 15 | 16 | # Expand relative path. This is important if the provided path contains a tilde (~) 17 | get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) 18 | 19 | file(DOWNLOAD 20 | https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake 21 | ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} 22 | ) 23 | 24 | include(${CPM_DOWNLOAD_LOCATION}) 25 | -------------------------------------------------------------------------------- /cmd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | PROJECT(flua) 4 | 5 | #add gflags 6 | CPMAddPackage( 7 | NAME gflags 8 | GITHUB_REPOSITORY gflags/gflags 9 | GIT_TAG v2.2.2 10 | OPTIONS 11 | "BUILD_SHARED_LIBS OFF" 12 | "INSTALL_HEADERS ON" 13 | "INSTALL_SHARED_LIBS ON" 14 | "INSTALL_STATIC_LIBS ON" 15 | "REGISTER_INSTALL_PREFIX ON" 16 | "BUILD_TESTING OFF" 17 | ) 18 | 19 | aux_source_directory(./ LUA_SRC_LIST) 20 | include_directories(./) 21 | include_directories(../include) 22 | 23 | IF (WIN32) 24 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-all-symbols") 25 | ELSE () 26 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-E") 27 | ENDIF () 28 | 29 | add_executable(flua ${LUA_SRC_LIST}) 30 | 31 | target_link_libraries(flua PRIVATE fakelua gflags::gflags gccjit) 32 | -------------------------------------------------------------------------------- /cmd/main.cpp: -------------------------------------------------------------------------------- 1 | #include "fakelua.h" 2 | #include "gflags/gflags.h" 3 | #include 4 | 5 | using namespace fakelua; 6 | 7 | // register some global flags 8 | DEFINE_bool(debug, false, "enable debug mode"); 9 | DEFINE_string(entry, "main", "entry function name, entry must return code(int) and has no parameter"); 10 | DEFINE_int32(repeat, 1, "the repeat run main function times"); 11 | 12 | int main(int argc, char **argv) { 13 | gflags::SetUsageMessage("usage: ./flua --help\n" 14 | "\n"); 15 | gflags::SetVersionString("0.0.1"); 16 | gflags::ParseCommandLineFlags(&argc, (char ***) &argv, true); 17 | 18 | if (argc < 2) { 19 | std::cout << gflags::ProgramUsage() << std::endl; 20 | return 0; 21 | } 22 | 23 | auto L = fakelua_newstate(); 24 | L->compile_file(argv[1], {debug_mode: FLAGS_debug}); 25 | 26 | int code = 0; 27 | for (int i = 0; i < FLAGS_repeat; i++) { 28 | L->call(FLAGS_entry, std::tie(code)); 29 | } 30 | std::cout << "code: " << code << std::endl; 31 | 32 | return code; 33 | } 34 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | project(libfakelua) 4 | 5 | #add magic_enum 6 | CPMAddPackage( 7 | NAME magic_enum 8 | GITHUB_REPOSITORY Neargye/magic_enum 9 | VERSION 0.9.5 10 | ) 11 | include_directories(${magic_enum_SOURCE_DIR}/include/magic_enum) 12 | 13 | aux_source_directory(compile/bison FAKELUA_SRC_LIST) 14 | aux_source_directory(compile/flex FAKELUA_SRC_LIST) 15 | aux_source_directory(./compile FAKELUA_SRC_LIST) 16 | aux_source_directory(./state FAKELUA_SRC_LIST) 17 | aux_source_directory(./util FAKELUA_SRC_LIST) 18 | aux_source_directory(./fakelua FAKELUA_SRC_LIST) 19 | aux_source_directory(./jit FAKELUA_SRC_LIST) 20 | aux_source_directory(./var FAKELUA_SRC_LIST) 21 | aux_source_directory(./ FAKELUA_SRC_LIST) 22 | include_directories(./) 23 | include_directories(../include) 24 | include_directories(./platform) 25 | add_library(fakelua SHARED ${FAKELUA_SRC_LIST}) 26 | 27 | IF (WIN32) 28 | set(TARGET_LIB gccjit) 29 | ENDIF () 30 | 31 | if (USE_COV) 32 | set(TARGET_LIB ${TARGET_LIB} gcov) 33 | endif () 34 | 35 | target_link_libraries(fakelua ${TARGET_LIB}) 36 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Directory structure 2 | * [compile](./compile) use flex bison to lexing parsing lua code 3 | * [fakelua](./fakelua) some global code 4 | * [jit](./jit) use the gccjit library to generate native code 5 | * [platform](./platform) platform code, use cross platform 6 | * [state](./state) lua state code, and some state subclass 7 | * [util](./util) some util code, like memory pool 8 | * [var](./var) the lua variable code, like table, string, number, etc 9 | -------------------------------------------------------------------------------- /src/compile/README.md: -------------------------------------------------------------------------------- 1 | # The Complete Syntax of Lua 2 | ``` 3 | chunk ::= block 4 | 5 | block ::= {stat} [retstat] 6 | 7 | stat ::= ‘;’ | 8 | varlist ‘=’ explist | 9 | functioncall | 10 | label | 11 | break | 12 | goto Name | 13 | do block end | 14 | while exp do block end | 15 | repeat block until exp | 16 | if exp then block {elseif exp then block} [else block] end | 17 | for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | 18 | for namelist in explist do block end | 19 | function funcname funcbody | 20 | local function Name funcbody | 21 | local attnamelist [‘=’ explist] 22 | 23 | attnamelist ::= Name attrib {‘,’ Name attrib} 24 | 25 | attrib ::= [‘<’ Name ‘>’] 26 | 27 | retstat ::= return [explist] [‘;’] 28 | 29 | label ::= ‘::’ Name ‘::’ 30 | 31 | funcname ::= Name {‘.’ Name} [‘:’ Name] 32 | 33 | varlist ::= var {‘,’ var} 34 | 35 | var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 36 | 37 | namelist ::= Name {‘,’ Name} 38 | 39 | explist ::= exp {‘,’ exp} 40 | 41 | exp ::= nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | 42 | prefixexp | tableconstructor | exp binop exp | unop exp 43 | 44 | prefixexp ::= var | functioncall | ‘(’ exp ‘)’ 45 | 46 | functioncall ::= prefixexp args | prefixexp ‘:’ Name args 47 | 48 | args ::= ‘(’ [explist] ‘)’ | tableconstructor | LiteralString 49 | 50 | functiondef ::= function funcbody 51 | 52 | funcbody ::= ‘(’ [parlist] ‘)’ block end 53 | 54 | parlist ::= namelist [‘,’ ‘...’] | ‘...’ 55 | 56 | tableconstructor ::= ‘{’ [fieldlist] ‘}’ 57 | 58 | fieldlist ::= field {fieldsep field} [fieldsep] 59 | 60 | field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp 61 | 62 | fieldsep ::= ‘,’ | ‘;’ 63 | 64 | binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | 65 | ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | 66 | ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 67 | and | or 68 | 69 | unop ::= ‘-’ | not | ‘#’ | ‘~’ 70 | ``` -------------------------------------------------------------------------------- /src/compile/bison/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | set -x 3 | 4 | bison parser.y --html --graph --header=parser.h -o parser.cpp 5 | export LC_ALL=en_US.UTF-8 6 | bison parser.y --html --graph --header=parser.h -o parser.cpp 7 | -------------------------------------------------------------------------------- /src/compile/bison/location.hh: -------------------------------------------------------------------------------- 1 | // A Bison parser, made by GNU Bison 3.8. 2 | 3 | // Locations for Bison parsers in C++ 4 | 5 | // Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc. 6 | 7 | // This program is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | 17 | // You should have received a copy of the GNU General Public License 18 | // along with this program. If not, see . 19 | 20 | // As a special exception, you may create a larger work that contains 21 | // part or all of the Bison parser skeleton and distribute that work 22 | // under terms of your choice, so long as that work isn't itself a 23 | // parser generator using the skeleton or a modified version thereof 24 | // as a parser skeleton. Alternatively, if you modify or redistribute 25 | // the parser skeleton itself, you may (at your option) remove this 26 | // special exception, which will cause the skeleton and the resulting 27 | // Bison output files to be licensed under the GNU General Public 28 | // License without this special exception. 29 | 30 | // This special exception was added by the Free Software Foundation in 31 | // version 2.2 of Bison. 32 | 33 | /** 34 | ** \file location.hh 35 | ** Define the yy::location class. 36 | */ 37 | 38 | #ifndef YY_YY_LOCATION_HH_INCLUDED 39 | # define YY_YY_LOCATION_HH_INCLUDED 40 | 41 | # include 42 | # include 43 | 44 | # ifndef YY_NULLPTR 45 | # if defined __cplusplus 46 | # if 201103L <= __cplusplus 47 | # define YY_NULLPTR nullptr 48 | # else 49 | # define YY_NULLPTR 0 50 | # endif 51 | # else 52 | # define YY_NULLPTR ((void*)0) 53 | # endif 54 | # endif 55 | 56 | namespace yy { 57 | #line 58 "location.hh" 58 | 59 | /// A point in a source file. 60 | class position 61 | { 62 | public: 63 | /// Type for file name. 64 | typedef const std::string filename_type; 65 | /// Type for line and column numbers. 66 | typedef int counter_type; 67 | 68 | /// Construct a position. 69 | explicit position (filename_type* f = YY_NULLPTR, 70 | counter_type l = 1, 71 | counter_type c = 1) 72 | : filename (f) 73 | , line (l) 74 | , column (c) 75 | {} 76 | 77 | 78 | /// Initialization. 79 | void initialize (filename_type* fn = YY_NULLPTR, 80 | counter_type l = 1, 81 | counter_type c = 1) 82 | { 83 | filename = fn; 84 | line = l; 85 | column = c; 86 | } 87 | 88 | /** \name Line and Column related manipulators 89 | ** \{ */ 90 | /// (line related) Advance to the COUNT next lines. 91 | void lines (counter_type count = 1) 92 | { 93 | if (count) 94 | { 95 | column = 1; 96 | line = add_ (line, count, 1); 97 | } 98 | } 99 | 100 | /// (column related) Advance to the COUNT next columns. 101 | void columns (counter_type count = 1) 102 | { 103 | column = add_ (column, count, 1); 104 | } 105 | /** \} */ 106 | 107 | /// File name to which this position refers. 108 | filename_type* filename; 109 | /// Current line number. 110 | counter_type line; 111 | /// Current column number. 112 | counter_type column; 113 | 114 | private: 115 | /// Compute max (min, lhs+rhs). 116 | static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min) 117 | { 118 | return lhs + rhs < min ? min : lhs + rhs; 119 | } 120 | }; 121 | 122 | /// Add \a width columns, in place. 123 | inline position& 124 | operator+= (position& res, position::counter_type width) 125 | { 126 | res.columns (width); 127 | return res; 128 | } 129 | 130 | /// Add \a width columns. 131 | inline position 132 | operator+ (position res, position::counter_type width) 133 | { 134 | return res += width; 135 | } 136 | 137 | /// Subtract \a width columns, in place. 138 | inline position& 139 | operator-= (position& res, position::counter_type width) 140 | { 141 | return res += -width; 142 | } 143 | 144 | /// Subtract \a width columns. 145 | inline position 146 | operator- (position res, position::counter_type width) 147 | { 148 | return res -= width; 149 | } 150 | 151 | /** \brief Intercept output stream redirection. 152 | ** \param ostr the destination output stream 153 | ** \param pos a reference to the position to redirect 154 | */ 155 | template 156 | std::basic_ostream& 157 | operator<< (std::basic_ostream& ostr, const position& pos) 158 | { 159 | if (pos.filename) 160 | ostr << *pos.filename << ':'; 161 | return ostr << pos.line << '.' << pos.column; 162 | } 163 | 164 | /// Two points in a source file. 165 | class location 166 | { 167 | public: 168 | /// Type for file name. 169 | typedef position::filename_type filename_type; 170 | /// Type for line and column numbers. 171 | typedef position::counter_type counter_type; 172 | 173 | /// Construct a location from \a b to \a e. 174 | location (const position& b, const position& e) 175 | : begin (b) 176 | , end (e) 177 | {} 178 | 179 | /// Construct a 0-width location in \a p. 180 | explicit location (const position& p = position ()) 181 | : begin (p) 182 | , end (p) 183 | {} 184 | 185 | /// Construct a 0-width location in \a f, \a l, \a c. 186 | explicit location (filename_type* f, 187 | counter_type l = 1, 188 | counter_type c = 1) 189 | : begin (f, l, c) 190 | , end (f, l, c) 191 | {} 192 | 193 | 194 | /// Initialization. 195 | void initialize (filename_type* f = YY_NULLPTR, 196 | counter_type l = 1, 197 | counter_type c = 1) 198 | { 199 | begin.initialize (f, l, c); 200 | end = begin; 201 | } 202 | 203 | /** \name Line and Column related manipulators 204 | ** \{ */ 205 | public: 206 | /// Reset initial location to final location. 207 | void step () 208 | { 209 | begin = end; 210 | } 211 | 212 | /// Extend the current location to the COUNT next columns. 213 | void columns (counter_type count = 1) 214 | { 215 | end += count; 216 | } 217 | 218 | /// Extend the current location to the COUNT next lines. 219 | void lines (counter_type count = 1) 220 | { 221 | end.lines (count); 222 | } 223 | /** \} */ 224 | 225 | 226 | public: 227 | /// Beginning of the located region. 228 | position begin; 229 | /// End of the located region. 230 | position end; 231 | }; 232 | 233 | /// Join two locations, in place. 234 | inline location& 235 | operator+= (location& res, const location& end) 236 | { 237 | res.end = end.end; 238 | return res; 239 | } 240 | 241 | /// Join two locations. 242 | inline location 243 | operator+ (location res, const location& end) 244 | { 245 | return res += end; 246 | } 247 | 248 | /// Add \a width columns to the end position, in place. 249 | inline location& 250 | operator+= (location& res, location::counter_type width) 251 | { 252 | res.columns (width); 253 | return res; 254 | } 255 | 256 | /// Add \a width columns to the end position. 257 | inline location 258 | operator+ (location res, location::counter_type width) 259 | { 260 | return res += width; 261 | } 262 | 263 | /// Subtract \a width columns to the end position, in place. 264 | inline location& 265 | operator-= (location& res, location::counter_type width) 266 | { 267 | return res += -width; 268 | } 269 | 270 | /// Subtract \a width columns to the end position. 271 | inline location 272 | operator- (location res, location::counter_type width) 273 | { 274 | return res -= width; 275 | } 276 | 277 | /** \brief Intercept output stream redirection. 278 | ** \param ostr the destination output stream 279 | ** \param loc a reference to the location to redirect 280 | ** 281 | ** Avoid duplicate information. 282 | */ 283 | template 284 | std::basic_ostream& 285 | operator<< (std::basic_ostream& ostr, const location& loc) 286 | { 287 | location::counter_type end_col 288 | = 0 < loc.end.column ? loc.end.column - 1 : 0; 289 | ostr << loc.begin; 290 | if (loc.end.filename 291 | && (!loc.begin.filename 292 | || *loc.begin.filename != *loc.end.filename)) 293 | ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; 294 | else if (loc.begin.line < loc.end.line) 295 | ostr << '-' << loc.end.line << '.' << end_col; 296 | else if (loc.begin.column < end_col) 297 | ostr << '-' << end_col; 298 | return ostr; 299 | } 300 | 301 | } // yy 302 | #line 303 "location.hh" 303 | 304 | #endif // !YY_YY_LOCATION_HH_INCLUDED 305 | -------------------------------------------------------------------------------- /src/compile/compile_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace fakelua { 7 | 8 | }// namespace fakelua -------------------------------------------------------------------------------- /src/compile/compiler.cpp: -------------------------------------------------------------------------------- 1 | #include "compile/compiler.h" 2 | #include "bison/parser.h" 3 | #include "jit/preprocessor.h" 4 | #include "util/exception.h" 5 | 6 | namespace fakelua { 7 | 8 | compile_result compiler::compile_file(fakelua_state_ptr sp, const std::string &file, compile_config cfg) { 9 | LOG_INFO("start compile_file {}", file); 10 | myflexer f; 11 | f.input_file(file); 12 | return compile(sp, f, cfg); 13 | } 14 | 15 | compile_result compiler::compile_string(fakelua_state_ptr sp, const std::string &str, compile_config cfg) { 16 | LOG_INFO("start compile_string"); 17 | myflexer f; 18 | f.input_string(str); 19 | return compile(sp, f, cfg); 20 | } 21 | 22 | compile_result compiler::compile(fakelua_state_ptr sp, myflexer &f, compile_config cfg) { 23 | LOG_INFO("start compile {}", f.get_filename()); 24 | 25 | compile_result ret; 26 | 27 | ret.file_name = f.get_filename(); 28 | 29 | // generate the tree 30 | yy::parser parse(&f); 31 | auto code = parse.parse(); 32 | LOG_INFO("compile ret {}", code); 33 | DEBUG_ASSERT(code == 0); 34 | ret.chunk = f.get_chunk(); 35 | 36 | if (cfg.debug_mode) { 37 | // just walk the tree, do nothing 38 | walk_syntax_tree(ret.chunk, [](const syntax_tree_interface_ptr &ptr) {}); 39 | } 40 | 41 | // compile tree 42 | if (!cfg.skip_jit) { 43 | // preprocess 44 | pre_processor pp; 45 | pp.process(sp, cfg, ret.file_name, ret.chunk); 46 | 47 | // compile 48 | gcc_jitter jitter; 49 | jitter.compile(sp, cfg, ret.file_name, ret.chunk); 50 | } 51 | 52 | return ret; 53 | } 54 | 55 | }// namespace fakelua 56 | -------------------------------------------------------------------------------- /src/compile/compiler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "bison/parser.h" 4 | #include "compile/myflexer.h" 5 | #include "compile_common.h" 6 | #include "jit/gcc_jit.h" 7 | #include 8 | #include 9 | 10 | namespace fakelua { 11 | 12 | struct compile_result { 13 | // the file name 14 | std::string file_name; 15 | // the main syntax tree 16 | syntax_tree_interface_ptr chunk; 17 | }; 18 | 19 | // lua compiler class, parse lua code to syntax tree, and then compile to toy-interpreter runtime, and JIT binary code 20 | class compiler { 21 | public: 22 | compiler() = default; 23 | 24 | ~compiler() = default; 25 | 26 | public: 27 | // compile the lua file 28 | compile_result compile_file(fakelua_state_ptr sp, const std::string &file, compile_config cfg); 29 | 30 | // compile the lua string 31 | compile_result compile_string(fakelua_state_ptr sp, const std::string &str, compile_config cfg); 32 | 33 | private: 34 | // compile the myflexer which already input the file or string 35 | compile_result compile(fakelua_state_ptr sp, myflexer &f, compile_config cfg); 36 | }; 37 | 38 | }// namespace fakelua -------------------------------------------------------------------------------- /src/compile/flex/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | set -x 3 | flex++ -oscanner.cpp scanner.l 4 | -------------------------------------------------------------------------------- /src/compile/flex/scanner.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "compile/bison/parser.h" 8 | #include "compile/myflexer.h" 9 | 10 | // https://westes.github.io/flex/manual/Cxx.html 11 | 12 | // Give Flex the prototype of yylex we want ... 13 | # define YY_DECL \ 14 | yy::parser::symbol_type fakelua::myflexer::my_yylex() 15 | 16 | %} 17 | 18 | %{ 19 | 20 | #define FLEX_VERSION (YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION) 21 | 22 | %} 23 | 24 | %option c++ noyywrap nounput noinput batch debug yylineno 25 | %x SINGLE_LINE_COMMENT_STATE 26 | %x MULTI_LINE_COMMENT_STATE 27 | 28 | %{ 29 | 30 | %} 31 | 32 | string1 \"((?:\\\"|[^\"\n])*)\" 33 | string2 \'((\\'|[^'\n])*)\' 34 | string3 \[\[([^\]]|(\][^\]]))*\]\] 35 | string {string1}|{string2}|{string3} 36 | name [_a-zA-Z][_a-zA-Z0-9]{0,30} 37 | num1 [+-]?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)? 38 | num2 [+-]?0[xX][0-9a-fA-F]+(\.[0-9a-fA-F]+)?([pP][+-]?[0-9]+)? 39 | number {num1}|{num2} 40 | 41 | %{ 42 | // Code run each time a pattern is matched. 43 | # define YY_USER_ACTION loc.columns (yyleng); 44 | %} 45 | 46 | %% 47 | 48 | %{ 49 | yy::location& loc = location_; 50 | // Code run each time yylex is called. 51 | loc.step (); 52 | %} 53 | 54 | "--[[" { yy_push_state(MULTI_LINE_COMMENT_STATE); } 55 | "--]]" { yy_pop_state(); } 56 | \n { loc.lines(yyleng); loc.step(); } 57 | . { } 58 | 59 | "--" { yy_push_state(SINGLE_LINE_COMMENT_STATE); } 60 | \n { loc.lines(yyleng); loc.step(); yy_pop_state(); } 61 | . { } 62 | 63 | [ \t]+ loc.step (); 64 | \n+ loc.lines(yyleng); loc.step(); 65 | \r+ {} 66 | 67 | "%" return yy::parser::make_MOD(loc); 68 | "&" return yy::parser::make_BITAND(loc); 69 | "|" return yy::parser::make_BITOR(loc); 70 | "~" return yy::parser::make_BITNOT(loc); 71 | ">" return yy::parser::make_MORE(loc); 72 | "<" return yy::parser::make_LESS(loc); 73 | "#" return yy::parser::make_NUMBER_SIGN(loc); 74 | "^" return yy::parser::make_POW(loc); 75 | ";" return yy::parser::make_SEMICOLON(loc); 76 | ":" return yy::parser::make_COLON(loc); 77 | "," return yy::parser::make_COMMA(loc); 78 | "." return yy::parser::make_DOT(loc); 79 | ".." return yy::parser::make_CONCAT(loc); 80 | "..." return yy::parser::make_VAR_PARAMS(loc); 81 | "==" return yy::parser::make_EQUAL(loc); 82 | ">=" return yy::parser::make_MORE_EQUAL(loc); 83 | "<=" return yy::parser::make_LESS_EQUAL(loc); 84 | "~=" return yy::parser::make_NOT_EQUAL(loc); 85 | "<<" return yy::parser::make_LEFT_SHIFT(loc); 86 | ">>" return yy::parser::make_RIGHT_SHIFT(loc); 87 | "::" return yy::parser::make_GOTO_TAG(loc); 88 | "=" return yy::parser::make_ASSIGN(loc); 89 | "-" return yy::parser::make_MINUS(loc); 90 | "+" return yy::parser::make_PLUS(loc); 91 | "*" return yy::parser::make_STAR(loc); 92 | "/" return yy::parser::make_SLASH(loc); 93 | "(" return yy::parser::make_LPAREN(loc); 94 | ")" return yy::parser::make_RPAREN(loc); 95 | "{" return yy::parser::make_LCURLY(loc); 96 | "}" return yy::parser::make_RCURLY(loc); 97 | "[" return yy::parser::make_LSQUARE(loc); 98 | "]" return yy::parser::make_RSQUARE(loc); 99 | "and" return yy::parser::make_AND(loc); 100 | "break" return yy::parser::make_BREAK(loc); 101 | "do" return yy::parser::make_DO(loc); 102 | "else" return yy::parser::make_ELSE(loc); 103 | "elseif" return yy::parser::make_ELSEIF(loc); 104 | "end" return yy::parser::make_END(loc); 105 | "false" return yy::parser::make_FALSES(loc); 106 | "for" return yy::parser::make_FOR(loc); 107 | "function" return yy::parser::make_FUNCTION(loc); 108 | "goto" return yy::parser::make_GOTO(loc); 109 | "if" return yy::parser::make_IF(loc); 110 | "in" return yy::parser::make_IN(loc); 111 | "local" return yy::parser::make_LOCAL(loc); 112 | "nil" return yy::parser::make_NIL(loc); 113 | "not" return yy::parser::make_NOT(loc); 114 | "or" return yy::parser::make_OR(loc); 115 | "repeat" return yy::parser::make_REPEAT(loc); 116 | "return" return yy::parser::make_RETURN(loc); 117 | "then" return yy::parser::make_THEN(loc); 118 | "true" return yy::parser::make_TRUE(loc); 119 | "until" return yy::parser::make_UNTIL(loc); 120 | "while" return yy::parser::make_WHILE(loc); 121 | "//" return yy::parser::make_DOUBLE_SLASH(loc); 122 | 123 | {number} return yy::parser::make_NUMBER(yytext, loc); 124 | 125 | {name} return yy::parser::make_IDENTIFIER(yytext, loc); 126 | 127 | {string} return yy::parser::make_STRING(yytext, loc); 128 | 129 | . { throw yy::parser::syntax_error(loc, "invalid character: [" + std::string(yytext) + "]"); } 130 | 131 | <> return yy::parser::make_YYEOF (loc); 132 | 133 | %% 134 | -------------------------------------------------------------------------------- /src/compile/myflexer.cpp: -------------------------------------------------------------------------------- 1 | #include "compile/myflexer.h" 2 | #include "util/common.h" 3 | #include "util/exception.h" 4 | #include "util/file_util.h" 5 | 6 | namespace fakelua { 7 | 8 | myflexer::myflexer() { 9 | } 10 | 11 | myflexer::~myflexer() { 12 | } 13 | 14 | void myflexer::input_file(const std::string &file) { 15 | file_.open(file.data(), std::ios::binary); 16 | if (file_.fail()) { 17 | throw_fakelua_exception("open file failed " + file); 18 | } 19 | filename_ = file; 20 | location_.initialize(&filename_); 21 | set_debug(0); 22 | switch_streams(&file_, nullptr); 23 | } 24 | 25 | void myflexer::input_string(const std::string &str) { 26 | filename_ = generate_tmp_file(str); 27 | location_.initialize(&filename_); 28 | set_debug(0); 29 | string_ = std::istringstream(str.data(), std::ios::binary); 30 | switch_streams(&string_, nullptr); 31 | } 32 | 33 | void myflexer::set_chunk(const syntax_tree_interface_ptr &chunk) { 34 | chunk_ = chunk; 35 | } 36 | 37 | syntax_tree_interface_ptr myflexer::get_chunk() const { 38 | return chunk_; 39 | } 40 | 41 | std::string myflexer::remove_quotes(const std::string &str) { 42 | DEBUG_ASSERT(str.size() >= 2); 43 | if (str[0] == '\'' && str[str.size() - 1] == '\'') { 44 | // we need to replace escape chars in string 45 | return replace_escape_chars(str.substr(1, str.size() - 2)); 46 | } else if (str[0] == '"' && str[str.size() - 1] == '"') { 47 | // we need to replace escape chars in string 48 | return replace_escape_chars(str.substr(1, str.size() - 2)); 49 | } else { 50 | DEBUG_ASSERT(str.size() >= 4); 51 | DEBUG_ASSERT(str[0] == '[' && str[1] == '[' && str[str.size() - 1] == ']' && str[str.size() - 2] == ']'); 52 | // raw string not need to replace escape chars 53 | return str.substr(2, str.size() - 4); 54 | } 55 | } 56 | 57 | std::string myflexer::generate_tmp_file(const std::string &str) { 58 | // create tmp file in system temp dir 59 | std::string fileName = generate_tmp_filename("fakelua_myflexer_", ".lua"); 60 | std::ofstream file(fileName); 61 | DEBUG_ASSERT(file.is_open()); 62 | file << str; 63 | file.close(); 64 | return fileName; 65 | } 66 | 67 | }// namespace fakelua 68 | -------------------------------------------------------------------------------- /src/compile/myflexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if !defined(yyFlexLexerOnce) 4 | 5 | #include 6 | 7 | #endif 8 | 9 | #include "bison/parser.h" 10 | #include "syntax_tree.h" 11 | #include 12 | #include 13 | 14 | namespace fakelua { 15 | 16 | // create our flexer to use new yylex function my_yylex(), and receive the syntax tree 17 | class myflexer : public yyFlexLexer { 18 | public: 19 | myflexer(); 20 | 21 | virtual ~myflexer(); 22 | 23 | public: 24 | // implement in scanner.cpp 25 | yy::parser::symbol_type my_yylex(); 26 | 27 | // set the input lua file 28 | void input_file(const std::string &file); 29 | 30 | // set the input lua string 31 | void input_string(const std::string &str); 32 | 33 | // set the main syntax tree from parser 34 | void set_chunk(const syntax_tree_interface_ptr &chunk); 35 | 36 | // get the main syntax tree 37 | syntax_tree_interface_ptr get_chunk() const; 38 | 39 | // remove string quotes 40 | std::string remove_quotes(const std::string &str); 41 | 42 | // get the filename 43 | std::string get_filename() const { 44 | return filename_; 45 | } 46 | 47 | private: 48 | std::string generate_tmp_file(const std::string &str); 49 | 50 | private: 51 | // The token's location used by the scanner. 52 | yy::location location_; 53 | // The name of the file being parsed. 54 | std::string filename_; 55 | // The file being parsed. 56 | std::ifstream file_; 57 | // The string being parsed. 58 | std::istringstream string_; 59 | // The syntax tree from parser. 60 | syntax_tree_interface_ptr chunk_; 61 | }; 62 | 63 | }// namespace fakelua 64 | -------------------------------------------------------------------------------- /src/fakelua/fakelua.cpp: -------------------------------------------------------------------------------- 1 | #include "fakelua.h" 2 | #include "state/state.h" 3 | #include "util/common.h" 4 | 5 | namespace fakelua { 6 | 7 | namespace inter { 8 | 9 | var *native_to_fakelua_nil(fakelua_state_ptr s) { 10 | return &const_null_var; 11 | } 12 | 13 | var *native_to_fakelua_bool(fakelua_state_ptr s, bool v) { 14 | if (v) { 15 | return &const_true_var; 16 | } else { 17 | return &const_false_var; 18 | } 19 | } 20 | 21 | var *native_to_fakelua_char(fakelua_state_ptr s, char v) { 22 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 23 | ret->set_int(v); 24 | return ret; 25 | } 26 | 27 | var *native_to_fakelua_uchar(fakelua_state_ptr s, unsigned char v) { 28 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 29 | ret->set_int(v); 30 | return ret; 31 | } 32 | 33 | var *native_to_fakelua_short(fakelua_state_ptr s, short v) { 34 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 35 | ret->set_int(v); 36 | return ret; 37 | } 38 | 39 | var *native_to_fakelua_ushort(fakelua_state_ptr s, unsigned short v) { 40 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 41 | ret->set_int(v); 42 | return ret; 43 | } 44 | 45 | var *native_to_fakelua_int(fakelua_state_ptr s, int v) { 46 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 47 | ret->set_int(v); 48 | return ret; 49 | } 50 | 51 | var *native_to_fakelua_uint(fakelua_state_ptr s, unsigned int v) { 52 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 53 | ret->set_int(v); 54 | return ret; 55 | } 56 | 57 | var *native_to_fakelua_long(fakelua_state_ptr s, long v) { 58 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 59 | ret->set_int(v); 60 | return ret; 61 | } 62 | 63 | var *native_to_fakelua_ulong(fakelua_state_ptr s, unsigned long v) { 64 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 65 | ret->set_int(v); 66 | return ret; 67 | } 68 | 69 | var *native_to_fakelua_longlong(fakelua_state_ptr s, long long v) { 70 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 71 | ret->set_int(v); 72 | return ret; 73 | } 74 | 75 | var *native_to_fakelua_ulonglong(fakelua_state_ptr s, unsigned long long v) { 76 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 77 | ret->set_int(v); 78 | return ret; 79 | } 80 | 81 | var *native_to_fakelua_float(fakelua_state_ptr s, float v) { 82 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 83 | ret->set_float(v); 84 | return ret; 85 | } 86 | 87 | var *native_to_fakelua_double(fakelua_state_ptr s, double v) { 88 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 89 | ret->set_float(v); 90 | return ret; 91 | } 92 | 93 | var *native_to_fakelua_cstr(fakelua_state_ptr s, const char *v) { 94 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 95 | ret->set_string(s, v); 96 | return ret; 97 | } 98 | 99 | var *native_to_fakelua_str(fakelua_state_ptr s, char *v) { 100 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 101 | ret->set_string(s, v); 102 | return ret; 103 | } 104 | 105 | var *native_to_fakelua_string(fakelua_state_ptr s, const std::string &v) { 106 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 107 | ret->set_string(s, v); 108 | return ret; 109 | } 110 | 111 | var *native_to_fakelua_stringview(fakelua_state_ptr s, const std::string_view &v) { 112 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 113 | ret->set_string(s, v); 114 | return ret; 115 | } 116 | 117 | void vi_to_var(fakelua_state_ptr s, var_interface *src, var *dst) { 118 | DEBUG_ASSERT(src->vi_get_type() >= var_interface::type::MIN && src->vi_get_type() <= var_interface::type::MAX); 119 | switch (src->vi_get_type()) { 120 | case var_interface::type::NIL: 121 | dst->set_nil(); 122 | break; 123 | case var_interface::type::BOOL: 124 | dst->set_bool(src->vi_get_bool()); 125 | break; 126 | case var_interface::type::INT: 127 | dst->set_int(src->vi_get_int()); 128 | break; 129 | case var_interface::type::FLOAT: 130 | dst->set_float(src->vi_get_float()); 131 | break; 132 | case var_interface::type::STRING: 133 | dst->set_string(s, src->vi_get_string()); 134 | break; 135 | case var_interface::type::TABLE: 136 | dst->set_table(); 137 | for (int i = 0; i < src->vi_get_table_size(); ++i) { 138 | auto kv = src->vi_get_table_kv(i); 139 | auto k = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 140 | auto v = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 141 | vi_to_var(s, kv.first, k); 142 | vi_to_var(s, kv.second, v); 143 | dst->get_table().set(k, v); 144 | } 145 | break; 146 | } 147 | } 148 | 149 | var *native_to_fakelua_obj(fakelua_state_ptr s, var_interface *v) { 150 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 151 | vi_to_var(s, v, ret); 152 | return ret; 153 | } 154 | 155 | bool fakelua_to_native_bool(fakelua_state_ptr s, var *v) { 156 | if (v->type() == var_type::VAR_BOOL) { 157 | return v->get_bool(); 158 | } 159 | throw_fakelua_exception(std::format("fakelua_to_native_bool failed, type is {}", magic_enum::enum_name(v->type()))); 160 | } 161 | 162 | char fakelua_to_native_char(fakelua_state_ptr s, var *v) { 163 | if (v->type() == var_type::VAR_INT) { 164 | return v->get_int(); 165 | } 166 | throw_fakelua_exception(std::format("fakelua_to_native_char failed, type is {}", magic_enum::enum_name(v->type()))); 167 | } 168 | 169 | unsigned char fakelua_to_native_uchar(fakelua_state_ptr s, var *v) { 170 | if (v->type() == var_type::VAR_INT) { 171 | return v->get_int(); 172 | } 173 | throw_fakelua_exception(std::format("fakelua_to_native_uchar failed, type is {}", magic_enum::enum_name(v->type()))); 174 | } 175 | 176 | short fakelua_to_native_short(fakelua_state_ptr s, var *v) { 177 | if (v->type() == var_type::VAR_INT) { 178 | return v->get_int(); 179 | } 180 | throw_fakelua_exception(std::format("fakelua_to_native_short failed, type is {}", magic_enum::enum_name(v->type()))); 181 | } 182 | 183 | unsigned short fakelua_to_native_ushort(fakelua_state_ptr s, var *v) { 184 | if (v->type() == var_type::VAR_INT) { 185 | return v->get_int(); 186 | } 187 | throw_fakelua_exception(std::format("fakelua_to_native_ushort failed, type is {}", magic_enum::enum_name(v->type()))); 188 | } 189 | 190 | int fakelua_to_native_int(fakelua_state_ptr s, var *v) { 191 | if (v->type() == var_type::VAR_INT) { 192 | return v->get_int(); 193 | } 194 | throw_fakelua_exception(std::format("fakelua_to_native_int failed, type is {}", magic_enum::enum_name(v->type()))); 195 | } 196 | 197 | unsigned int fakelua_to_native_uint(fakelua_state_ptr s, var *v) { 198 | if (v->type() == var_type::VAR_INT) { 199 | return v->get_int(); 200 | } 201 | throw_fakelua_exception(std::format("fakelua_to_native_uint failed, type is {}", magic_enum::enum_name(v->type()))); 202 | } 203 | 204 | long fakelua_to_native_long(fakelua_state_ptr s, var *v) { 205 | if (v->type() == var_type::VAR_INT) { 206 | return v->get_int(); 207 | } 208 | throw_fakelua_exception(std::format("fakelua_to_native_long failed, type is {}", magic_enum::enum_name(v->type()))); 209 | } 210 | 211 | unsigned long fakelua_to_native_ulong(fakelua_state_ptr s, var *v) { 212 | if (v->type() == var_type::VAR_INT) { 213 | return v->get_int(); 214 | } 215 | throw_fakelua_exception(std::format("fakelua_to_native_ulong failed, type is {}", magic_enum::enum_name(v->type()))); 216 | } 217 | 218 | long long fakelua_to_native_longlong(fakelua_state_ptr s, var *v) { 219 | if (v->type() == var_type::VAR_INT) { 220 | return v->get_int(); 221 | } 222 | throw_fakelua_exception(std::format("fakelua_to_native_longlong failed, type is {}", magic_enum::enum_name(v->type()))); 223 | } 224 | 225 | unsigned long long fakelua_to_native_ulonglong(fakelua_state_ptr s, var *v) { 226 | if (v->type() == var_type::VAR_INT) { 227 | return v->get_int(); 228 | } 229 | throw_fakelua_exception(std::format("fakelua_to_native_ulonglong failed, type is {}", magic_enum::enum_name(v->type()))); 230 | } 231 | 232 | float fakelua_to_native_float(fakelua_state_ptr s, var *v) { 233 | if (v->type() == var_type::VAR_FLOAT) { 234 | return v->get_float(); 235 | } 236 | if (v->type() == var_type::VAR_INT) { 237 | return v->get_int(); 238 | } 239 | throw_fakelua_exception(std::format("fakelua_to_native_float failed, type is {}", magic_enum::enum_name(v->type()))); 240 | } 241 | 242 | double fakelua_to_native_double(fakelua_state_ptr s, var *v) { 243 | if (v->type() == var_type::VAR_FLOAT) { 244 | return v->get_float(); 245 | } 246 | if (v->type() == var_type::VAR_INT) { 247 | return v->get_int(); 248 | } 249 | throw_fakelua_exception(std::format("fakelua_to_native_double failed, type is {}", magic_enum::enum_name(v->type()))); 250 | } 251 | 252 | const char *fakelua_to_native_cstr(fakelua_state_ptr s, var *v) { 253 | if (v->type() == var_type::VAR_STRING) { 254 | return v->get_string().data(); 255 | } 256 | throw_fakelua_exception(std::format("fakelua_to_native_cstr failed, type is {}", magic_enum::enum_name(v->type()))); 257 | } 258 | 259 | const char *fakelua_to_native_str(fakelua_state_ptr s, var *v) { 260 | if (v->type() == var_type::VAR_STRING) { 261 | return v->get_string().data(); 262 | } 263 | throw_fakelua_exception(std::format("fakelua_to_native_str failed, type is {}", magic_enum::enum_name(v->type()))); 264 | } 265 | 266 | std::string fakelua_to_native_string(fakelua_state_ptr s, var *v) { 267 | if (v->type() == var_type::VAR_STRING) { 268 | return std::string(v->get_string()); 269 | } 270 | throw_fakelua_exception(std::format("fakelua_to_native_string failed, type is {}", magic_enum::enum_name(v->type()))); 271 | } 272 | 273 | std::string_view fakelua_to_native_stringview(fakelua_state_ptr s, var *v) { 274 | if (v->type() == var_type::VAR_STRING) { 275 | return v->get_string(); 276 | } 277 | throw_fakelua_exception(std::format("fakelua_to_native_stringview failed, type is {}", magic_enum::enum_name(v->type()))); 278 | } 279 | 280 | void var_to_vi(fakelua_state_ptr s, var *src, var_interface *dst) { 281 | DEBUG_ASSERT(src->type() >= var_type::VAR_MIN && src->type() <= var_type::VAR_MAX); 282 | switch (src->type()) { 283 | case var_type::VAR_NIL: 284 | dst->vi_set_nil(); 285 | break; 286 | case var_type::VAR_BOOL: 287 | dst->vi_set_bool(src->get_bool()); 288 | break; 289 | case var_type::VAR_INT: 290 | dst->vi_set_int(src->get_int()); 291 | break; 292 | case var_type::VAR_FLOAT: 293 | dst->vi_set_float(src->get_float()); 294 | break; 295 | case var_type::VAR_STRING: 296 | dst->vi_set_string(src->get_string()); 297 | break; 298 | case var_type::VAR_TABLE: { 299 | std::vector> kvs; 300 | src->get_table().range([&](var *k, var *v) { 301 | auto ki = std::dynamic_pointer_cast(s)->get_var_interface_new_func()(); 302 | auto vi = std::dynamic_pointer_cast(s)->get_var_interface_new_func()(); 303 | var_to_vi(s, k, ki); 304 | var_to_vi(s, v, vi); 305 | kvs.emplace_back(ki, vi); 306 | }); 307 | dst->vi_set_table(kvs); 308 | break; 309 | } 310 | } 311 | } 312 | 313 | var_interface *fakelua_to_native_obj(fakelua_state_ptr s, var *v) { 314 | auto ret = std::dynamic_pointer_cast(s)->get_var_interface_new_func()(); 315 | var_to_vi(s, v, ret); 316 | return ret; 317 | } 318 | 319 | var *fakelua_get_var_by_index(fakelua_state_ptr s, var *ret, size_t i) { 320 | DEBUG_ASSERT(ret); 321 | if (ret->type() == var_type::VAR_TABLE && ret->is_variadic()) { 322 | var tmp; 323 | tmp.set_int(i); 324 | return ret->get_table().get(&tmp); 325 | } else { 326 | if (i == 1) { 327 | return ret; 328 | } else { 329 | return &const_null_var; 330 | } 331 | } 332 | } 333 | 334 | void *get_func_addr(fakelua_state_ptr s, const std::string &name, int &arg_count, bool &is_variadic) { 335 | auto func = std::dynamic_pointer_cast(s)->get_vm().get_function(name); 336 | if (func) { 337 | arg_count = func->get_arg_count(); 338 | is_variadic = func->is_variadic(); 339 | return func->get_addr(); 340 | } 341 | return nullptr; 342 | } 343 | 344 | var *make_variadic_table(fakelua_state_ptr s, int start, int n, var **args) { 345 | auto ret = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 346 | ret->set_table(); 347 | for (int i = 0; i < n - start; i++) { 348 | auto key = std::dynamic_pointer_cast(s)->get_var_pool().alloc(); 349 | key->set_int(i + 1); 350 | auto v = args[start + i]; 351 | ret->get_table().set(key, v, true); 352 | } 353 | ret->set_variadic(true); 354 | return ret; 355 | } 356 | 357 | void reset(fakelua_state_ptr s) { 358 | std::dynamic_pointer_cast(s)->reset(); 359 | } 360 | 361 | [[noreturn]] void throw_inter_fakelua_exception(const std::string &msg) { 362 | throw_fakelua_exception(msg); 363 | } 364 | 365 | }// namespace inter 366 | 367 | fakelua_state_ptr fakelua_newstate() { 368 | LOG_INFO("fakelua_newstate"); 369 | return std::make_shared(); 370 | } 371 | 372 | void fakelua_state::set_debug_log_level(int level) { 373 | set_log_level((log_level) level); 374 | } 375 | 376 | }// namespace fakelua 377 | -------------------------------------------------------------------------------- /src/jit/gcc_jit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compile/compile_common.h" 4 | #include "compile/syntax_tree.h" 5 | #include "fakelua.h" 6 | #include "gcc_jit_handle.h" 7 | #include "var/var.h" 8 | #include "vm.h" 9 | #include 10 | 11 | namespace fakelua { 12 | 13 | typedef std::shared_ptr gccjit_context_ptr; 14 | 15 | class gcc_jitter { 16 | public: 17 | gcc_jitter() = default; 18 | 19 | ~gcc_jitter(); 20 | 21 | void compile(fakelua_state_ptr sp, compile_config cfg, const std::string &file_name, const syntax_tree_interface_ptr &chunk); 22 | 23 | private: 24 | void compile_const_defines(const syntax_tree_interface_ptr &chunk); 25 | 26 | void compile_const_define(const syntax_tree_interface_ptr &stmt); 27 | 28 | void compile_functions(const syntax_tree_interface_ptr &chunk); 29 | 30 | void compile_function(const std::string &name, const syntax_tree_interface_ptr &funcbody); 31 | 32 | std::string compile_funcname(const syntax_tree_interface_ptr &ptr); 33 | 34 | gccjit::rvalue compile_exp(gccjit::function &func, const syntax_tree_interface_ptr &exp); 35 | 36 | std::vector> compile_parlist(syntax_tree_interface_ptr parlist, int &is_variadic); 37 | 38 | void compile_stmt(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 39 | 40 | void compile_stmt_return(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 41 | 42 | std::vector compile_explist(gccjit::function &func, const syntax_tree_interface_ptr &explist); 43 | 44 | gccjit::rvalue compile_prefixexp(gccjit::function &func, const syntax_tree_interface_ptr &pe); 45 | 46 | gccjit::rvalue compile_var(gccjit::function &func, const syntax_tree_interface_ptr &v); 47 | 48 | gccjit::lvalue compile_var_lvalue(gccjit::function &func, const syntax_tree_interface_ptr &v); 49 | 50 | void compile_stmt_local_var(gccjit::function &function, const syntax_tree_interface_ptr &stmt); 51 | 52 | void compile_stmt_assign(gccjit::function &function, const syntax_tree_interface_ptr &stmt); 53 | 54 | std::vector compile_varlist_lvalue(gccjit::function &func, const syntax_tree_interface_ptr &explist); 55 | 56 | gccjit::rvalue compile_tableconstructor(gccjit::function &func, const syntax_tree_interface_ptr &tc); 57 | 58 | std::vector compile_fieldlist(gccjit::function &func, const syntax_tree_interface_ptr &fieldlist); 59 | 60 | std::pair compile_field(gccjit::function &func, const syntax_tree_interface_ptr &field); 61 | 62 | gccjit::rvalue compile_binop(gccjit::function &func, const syntax_tree_interface_ptr &left, const syntax_tree_interface_ptr &right, 63 | const syntax_tree_interface_ptr &op); 64 | 65 | gccjit::rvalue compile_unop(gccjit::function &func, const syntax_tree_interface_ptr &right, const syntax_tree_interface_ptr &op); 66 | 67 | gccjit::rvalue compile_functioncall(gccjit::function &func, const syntax_tree_interface_ptr &functioncall); 68 | 69 | std::vector compile_args(gccjit::function &func, const syntax_tree_interface_ptr &args); 70 | 71 | void compile_stmt_functioncall(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 72 | 73 | void compile_stmt_label(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 74 | 75 | void compile_stmt_block(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 76 | 77 | void compile_stmt_while(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 78 | 79 | void compile_stmt_repeat(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 80 | 81 | void compile_stmt_if(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 82 | 83 | void compile_stmt_break(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 84 | 85 | void compile_stmt_for_loop(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 86 | 87 | void compile_stmt_for_in(gccjit::function &func, const syntax_tree_interface_ptr &stmt); 88 | 89 | private: 90 | gccjit::location new_location(const syntax_tree_interface_ptr &ptr); 91 | 92 | std::string new_block_name(const std::string &name, const syntax_tree_interface_ptr &ptr); 93 | 94 | void call_global_init_func(); 95 | 96 | std::string location_str(const syntax_tree_interface_ptr &ptr); 97 | 98 | gccjit::lvalue find_lvalue_by_name(const std::string &name, const syntax_tree_interface_ptr &ptr); 99 | 100 | std::optional try_find_lvalue_by_name(const std::string &name, const syntax_tree_interface_ptr &ptr); 101 | 102 | void save_stack_lvalue_by_name(const std::string &name, const gccjit::lvalue &value, const syntax_tree_interface_ptr &ptr); 103 | 104 | [[noreturn]] void throw_error(const std::string &msg, const syntax_tree_interface_ptr &ptr); 105 | 106 | void check_return_block(gccjit::function &func, const syntax_tree_interface_ptr &ptr); 107 | 108 | bool is_block_ended(); 109 | 110 | private: 111 | bool is_simple_assign(const syntax_tree_interface_ptr &vars, const syntax_tree_interface_ptr &exps); 112 | 113 | bool is_simple_args(const syntax_tree_interface_ptr &args); 114 | 115 | bool is_simple_explist(const syntax_tree_interface_ptr &explist); 116 | 117 | bool is_simple_exp(const syntax_tree_interface_ptr &exp); 118 | 119 | bool is_simple_prefixexp(const syntax_tree_interface_ptr &pe); 120 | 121 | bool is_simple_tableconstructor(const syntax_tree_interface_ptr &tc); 122 | 123 | bool is_simple_field(const syntax_tree_interface_ptr &fieldlist); 124 | 125 | std::string get_simple_prefixexp_name(const syntax_tree_interface_ptr &pe); 126 | 127 | std::string get_simple_var_name(const syntax_tree_interface_ptr &v); 128 | 129 | bool is_jit_builtin_function(const std::string &name); 130 | 131 | std::string get_jit_builtin_function_vm_name(const std::string &name); 132 | 133 | private: 134 | // the state contains the running environment we need. 135 | fakelua_state_ptr sp_; 136 | // the compile config 137 | std::string file_name_; 138 | // gccjit context 139 | gccjit_context_ptr gccjit_context_; 140 | gcc_jit_handle_ptr gcc_jit_handle_; 141 | // function info save here 142 | struct function_info { 143 | int params_count = 0; 144 | bool is_variadic = false; 145 | gccjit::function func; 146 | }; 147 | // function name -> function info 148 | std::unordered_map function_infos_; 149 | // global const var name -> gcc_jit_lvalue 150 | std::unordered_map> global_const_vars_; 151 | // compiling function tmp data 152 | struct function_data { 153 | // save stack frame vars 154 | struct stack_frame { 155 | std::unordered_map local_vars; 156 | }; 157 | // every block stack frame 158 | std::vector stack_frames; 159 | // record the block ended 160 | std::unordered_set ended_blocks; 161 | // use to save the current block 162 | gccjit::block cur_block; 163 | // used for jmp to 164 | std::vector stack_end_blocks; 165 | // temp var name counter 166 | int pre_index = 0; 167 | // mark cur func if is const 168 | bool is_const = false; 169 | // current compiling function name 170 | std::string cur_function_name; 171 | // current compiling function 172 | gccjit::function cur_gccjit_func; 173 | }; 174 | // current compiling function data 175 | function_data cur_function_data_; 176 | // save the preprocess trunk new stmt 177 | std::vector preprocess_trunk_new_stmt_; 178 | }; 179 | 180 | typedef std::shared_ptr gcc_jitter_ptr; 181 | 182 | }// namespace fakelua 183 | -------------------------------------------------------------------------------- /src/jit/gcc_jit_handle.cpp: -------------------------------------------------------------------------------- 1 | #include "gcc_jit_handle.h" 2 | #include "state/state.h" 3 | 4 | namespace fakelua { 5 | 6 | gcc_jit_handle::gcc_jit_handle(fakelua_state *state) : state_(state) { 7 | } 8 | 9 | gcc_jit_handle::~gcc_jit_handle() { 10 | if (gccjit_result_) { 11 | gcc_jit_result_release(gccjit_result_); 12 | gccjit_result_ = nullptr; 13 | } 14 | if (gccjit_log_fp_) { 15 | fclose(gccjit_log_fp_); 16 | gccjit_log_fp_ = nullptr; 17 | } 18 | } 19 | 20 | std::string_view gcc_jit_handle::alloc_str(const std::string_view &name) { 21 | auto it = str_container_map_.find(name); 22 | if (it != str_container_map_.end()) { 23 | return *it; 24 | } 25 | 26 | const auto &ret = dynamic_cast(state_)->get_var_string_heap().alloc(name); 27 | str_container_map_.insert(ret); 28 | return ret; 29 | } 30 | 31 | var *gcc_jit_handle::alloc_var() { 32 | auto ret = std::make_shared(); 33 | ret->set_const(true); 34 | const_vars_.push_back(ret); 35 | return ret.get(); 36 | } 37 | 38 | }// namespace fakelua -------------------------------------------------------------------------------- /src/jit/gcc_jit_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "util/common.h" 4 | #include "var/var.h" 5 | #include 6 | 7 | namespace fakelua { 8 | 9 | class gcc_jit_handle { 10 | public: 11 | gcc_jit_handle(fakelua_state *state); 12 | 13 | ~gcc_jit_handle(); 14 | 15 | fakelua_state *get_state() { 16 | return state_; 17 | } 18 | 19 | void set_result(gcc_jit_result *result) { 20 | gccjit_result_ = result; 21 | } 22 | 23 | gcc_jit_result *get_result() { 24 | return gccjit_result_; 25 | } 26 | 27 | void set_log_fp(FILE *fp) { 28 | gccjit_log_fp_ = fp; 29 | } 30 | 31 | // alloc string used by the gcc_jit_result, the storage is also state's string pool 32 | std::string_view alloc_str(const std::string_view &name); 33 | 34 | // get all used string 35 | const std::unordered_set &get_str_container_map() const { 36 | return str_container_map_; 37 | } 38 | 39 | // alloc const var used by the gcc_jit_result 40 | var *alloc_var(); 41 | 42 | private: 43 | fakelua_state *state_; 44 | gcc_jit_result *gccjit_result_ = nullptr; 45 | FILE *gccjit_log_fp_ = nullptr; 46 | std::unordered_set str_container_map_; 47 | std::vector const_vars_; 48 | }; 49 | 50 | typedef std::shared_ptr gcc_jit_handle_ptr; 51 | 52 | }// namespace fakelua 53 | -------------------------------------------------------------------------------- /src/jit/preprocessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compile/compile_common.h" 4 | #include "compile/syntax_tree.h" 5 | #include "fakelua.h" 6 | #include "var/var.h" 7 | 8 | namespace fakelua { 9 | 10 | class pre_processor { 11 | public: 12 | pre_processor() = default; 13 | 14 | ~pre_processor(); 15 | 16 | void process(fakelua_state_ptr sp, compile_config cfg, const std::string &file_name, const syntax_tree_interface_ptr &chunk); 17 | 18 | private: 19 | void preprocess_const(const syntax_tree_interface_ptr &chunk); 20 | 21 | void preprocess_const_define(const syntax_tree_interface_ptr &stmt); 22 | 23 | void preprocess_functions_name(const syntax_tree_interface_ptr &chunk); 24 | 25 | void preprocess_function_name(const syntax_tree_interface_ptr &func); 26 | 27 | void save_preprocess_global_init(const syntax_tree_interface_ptr &chunk); 28 | 29 | void preprocess_table_assigns(const syntax_tree_interface_ptr &chunk); 30 | 31 | void preprocess_table_assign(const syntax_tree_interface_ptr &funcbody); 32 | 33 | void preprocess_extracts_literal_constants(const syntax_tree_interface_ptr &chunk); 34 | 35 | private: 36 | [[noreturn]] void throw_error(const std::string &msg, const syntax_tree_interface_ptr &ptr); 37 | 38 | std::string location_str(const syntax_tree_interface_ptr &ptr); 39 | 40 | void dump_debug_file(const syntax_tree_interface_ptr &chunk, int step); 41 | 42 | private: 43 | // the state contains the running environment we need. 44 | fakelua_state_ptr sp_; 45 | // the compile config 46 | std::string file_name_; 47 | // save the preprocess trunk new stmt in global_init func 48 | std::vector global_init_new_stmt_; 49 | // temp var name counter 50 | int pre_index_ = 0; 51 | }; 52 | 53 | }// namespace fakelua 54 | -------------------------------------------------------------------------------- /src/jit/vm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compile/syntax_tree.h" 4 | #include "fakelua.h" 5 | #include "gcc_jit_handle.h" 6 | #include "var/var.h" 7 | #include "vm_function.h" 8 | 9 | namespace fakelua { 10 | 11 | // store all compiled jit functions and some other running used data. 12 | // every state has one vm. 13 | class vm { 14 | public: 15 | vm() = default; 16 | 17 | ~vm() = default; 18 | 19 | // register function 20 | void register_function(const std::string &name, vm_function_ptr func) { 21 | vm_functions_[name] = func; 22 | } 23 | 24 | // get function 25 | vm_function_ptr get_function(const std::string &name) { 26 | auto iter = vm_functions_.find(name); 27 | if (iter == vm_functions_.end()) { 28 | return nullptr; 29 | } 30 | return iter->second; 31 | } 32 | 33 | // get all function 34 | const std::unordered_map &get_functions() { 35 | return vm_functions_; 36 | } 37 | 38 | // alloc global name, life cycle is all through the process, so put it in vm 39 | std::string alloc_global_name() { 40 | return std::format("__fakelua_global_{}__", global_name_++); 41 | } 42 | 43 | private: 44 | // all registered functions 45 | std::unordered_map vm_functions_; 46 | // global name counter 47 | uint64_t global_name_ = 0; 48 | }; 49 | 50 | extern "C" __attribute__((used)) var *new_var_nil(fakelua_state *s, gcc_jit_handle *h, bool is_const); 51 | 52 | extern "C" __attribute__((used)) var *new_var_false(fakelua_state *s, gcc_jit_handle *h, bool is_const); 53 | 54 | extern "C" __attribute__((used)) var *new_var_true(fakelua_state *s, gcc_jit_handle *h, bool is_const); 55 | 56 | extern "C" __attribute__((used)) var *new_var_int(fakelua_state *s, gcc_jit_handle *h, bool is_const, int64_t val); 57 | 58 | extern "C" __attribute__((used)) var *new_var_float(fakelua_state *s, gcc_jit_handle *h, bool is_const, double val); 59 | 60 | extern "C" __attribute__((used)) var *new_var_string(fakelua_state *s, gcc_jit_handle *h, bool is_const, const char *val, int len); 61 | 62 | extern "C" __attribute__((used)) var *new_var_table(fakelua_state *s, gcc_jit_handle *h, bool is_const, int n, ...); 63 | 64 | extern "C" __attribute__((used)) var *wrap_return_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, int n, ...); 65 | 66 | extern "C" __attribute__((used)) void assign_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, int left_n, int right_n, ...); 67 | 68 | extern "C" __attribute__((used)) var *binop_plus(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 69 | 70 | extern "C" __attribute__((used)) var *binop_plus(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 71 | 72 | extern "C" __attribute__((used)) var *binop_minus(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 73 | 74 | extern "C" __attribute__((used)) var *binop_star(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 75 | 76 | extern "C" __attribute__((used)) var *binop_slash(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 77 | 78 | extern "C" __attribute__((used)) var *binop_double_slash(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 79 | 80 | extern "C" __attribute__((used)) var *binop_pow(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 81 | 82 | extern "C" __attribute__((used)) var *binop_mod(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 83 | 84 | extern "C" __attribute__((used)) var *binop_bitand(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 85 | 86 | extern "C" __attribute__((used)) var *binop_xor(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 87 | 88 | extern "C" __attribute__((used)) var *binop_bitor(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 89 | 90 | extern "C" __attribute__((used)) var *binop_right_shift(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 91 | 92 | extern "C" __attribute__((used)) var *binop_left_shift(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 93 | 94 | extern "C" __attribute__((used)) var *binop_concat(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 95 | 96 | extern "C" __attribute__((used)) var *binop_less(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 97 | 98 | extern "C" __attribute__((used)) var *binop_less_equal(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 99 | 100 | extern "C" __attribute__((used)) var *binop_more(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 101 | 102 | extern "C" __attribute__((used)) var *binop_more_equal(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 103 | 104 | extern "C" __attribute__((used)) var *binop_equal(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 105 | 106 | extern "C" __attribute__((used)) var *binop_not_equal(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *l, var *r); 107 | 108 | extern "C" __attribute__((used)) bool test_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *v); 109 | 110 | extern "C" __attribute__((used)) bool test_not_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *v); 111 | 112 | extern "C" __attribute__((used)) var *unop_minus(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *r); 113 | 114 | extern "C" __attribute__((used)) var *unop_not(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *r); 115 | 116 | extern "C" __attribute__((used)) var *unop_number_sign(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *r); 117 | 118 | extern "C" __attribute__((used)) var *unop_bitnot(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *r); 119 | 120 | extern "C" __attribute__((used)) var *call_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *func, var *col_key, int n, ...); 121 | 122 | extern "C" __attribute__((used)) var *table_index_by_var(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table, var *key); 123 | 124 | extern "C" __attribute__((used)) var *table_index_by_name(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table, const char *key, 125 | int len); 126 | 127 | extern "C" __attribute__((used)) var *table_set(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table, var *key, var *val); 128 | 129 | extern "C" __attribute__((used)) size_t table_size(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table); 130 | 131 | extern "C" __attribute__((used)) var *table_key_by_pos(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table, size_t pos); 132 | 133 | extern "C" __attribute__((used)) var *table_value_by_pos(fakelua_state *s, gcc_jit_handle *h, bool is_const, var *table, size_t pos); 134 | 135 | }// namespace fakelua 136 | -------------------------------------------------------------------------------- /src/jit/vm_function.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compile/syntax_tree.h" 4 | #include "fakelua.h" 5 | #include "gcc_jit_handle.h" 6 | #include "var/var.h" 7 | 8 | namespace fakelua { 9 | 10 | // wrapper of gcc_jit_function call 11 | class vm_function { 12 | public: 13 | vm_function(gcc_jit_handle_ptr gcc_jit_handle, void *gcc_jit_func, int arg_count, bool is_variadic) 14 | : gcc_jit_handle_(gcc_jit_handle), gcc_jit_func_(gcc_jit_func), arg_count_(arg_count), is_variadic_(is_variadic) { 15 | } 16 | 17 | ~vm_function() = default; 18 | 19 | void *get_addr() { 20 | return gcc_jit_func_; 21 | } 22 | 23 | gcc_jit_handle_ptr get_gcc_jit_handle() { 24 | return gcc_jit_handle_; 25 | } 26 | 27 | int get_arg_count() { 28 | return arg_count_; 29 | } 30 | 31 | bool is_variadic() { 32 | return is_variadic_; 33 | } 34 | 35 | private: 36 | gcc_jit_handle_ptr gcc_jit_handle_; 37 | void *gcc_jit_func_ = nullptr; 38 | int arg_count_ = 0; 39 | bool is_variadic_ = false; 40 | }; 41 | 42 | typedef std::shared_ptr vm_function_ptr; 43 | 44 | }// namespace fakelua 45 | -------------------------------------------------------------------------------- /src/platform/FlexLexer.h: -------------------------------------------------------------------------------- 1 | // -*-C++-*- 2 | // FlexLexer.h -- define interfaces for lexical analyzer classes generated 3 | // by flex 4 | 5 | // Copyright (c) 1993 The Regents of the University of California. 6 | // All rights reserved. 7 | // 8 | // This code is derived from software contributed to Berkeley by 9 | // Kent Williams and Tom Epperly. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions 13 | // are met: 14 | 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 2. Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in the 19 | // documentation and/or other materials provided with the distribution. 20 | 21 | // Neither the name of the University nor the names of its contributors 22 | // may be used to endorse or promote products derived from this software 23 | // without specific prior written permission. 24 | 25 | // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 26 | // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 27 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 | // PURPOSE. 29 | 30 | // This file defines FlexLexer, an abstract class which specifies the 31 | // external interface provided to flex C++ lexer objects, and yyFlexLexer, 32 | // which defines a particular lexer class. 33 | // 34 | // If you want to create multiple lexer classes, you use the -P flag 35 | // to rename each yyFlexLexer to some other xxFlexLexer. You then 36 | // include in your other sources once per lexer class: 37 | // 38 | // #undef yyFlexLexer 39 | // #define yyFlexLexer xxFlexLexer 40 | // #include 41 | // 42 | // #undef yyFlexLexer 43 | // #define yyFlexLexer zzFlexLexer 44 | // #include 45 | // ... 46 | 47 | #ifndef __FLEX_LEXER_H 48 | // Never included before - need to define base class. 49 | #define __FLEX_LEXER_H 50 | 51 | #include 52 | 53 | extern "C++" { 54 | 55 | struct yy_buffer_state; 56 | typedef int yy_state_type; 57 | 58 | class FlexLexer 59 | { 60 | public: 61 | virtual ~FlexLexer() { } 62 | 63 | const char* YYText() const { return yytext; } 64 | int YYLeng() const { return yyleng; } 65 | 66 | virtual void 67 | yy_switch_to_buffer( yy_buffer_state* new_buffer ) = 0; 68 | virtual yy_buffer_state* yy_create_buffer( std::istream* s, int size ) = 0; 69 | virtual yy_buffer_state* yy_create_buffer( std::istream& s, int size ) = 0; 70 | virtual void yy_delete_buffer( yy_buffer_state* b ) = 0; 71 | virtual void yyrestart( std::istream* s ) = 0; 72 | virtual void yyrestart( std::istream& s ) = 0; 73 | 74 | virtual int yylex() = 0; 75 | 76 | // Call yylex with new input/output sources. 77 | int yylex( std::istream& new_in, std::ostream& new_out ) 78 | { 79 | switch_streams( new_in, new_out ); 80 | return yylex(); 81 | } 82 | 83 | int yylex( std::istream* new_in, std::ostream* new_out = 0) 84 | { 85 | switch_streams( new_in, new_out ); 86 | return yylex(); 87 | } 88 | 89 | // Switch to new input/output streams. A nil stream pointer 90 | // indicates "keep the current one". 91 | virtual void switch_streams( std::istream* new_in, 92 | std::ostream* new_out ) = 0; 93 | virtual void switch_streams( std::istream& new_in, 94 | std::ostream& new_out ) = 0; 95 | 96 | int lineno() const { return yylineno; } 97 | 98 | int debug() const { return yy_flex_debug; } 99 | void set_debug( int flag ) { yy_flex_debug = flag; } 100 | 101 | protected: 102 | char* yytext; 103 | int yyleng; 104 | int yylineno; // only maintained if you use %option yylineno 105 | int yy_flex_debug; // only has effect with -d or "%option debug" 106 | }; 107 | 108 | } 109 | #endif // FLEXLEXER_H 110 | 111 | #if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce) 112 | // Either this is the first time through (yyFlexLexerOnce not defined), 113 | // or this is a repeated include to define a different flavor of 114 | // yyFlexLexer, as discussed in the flex manual. 115 | # define yyFlexLexerOnce 116 | 117 | extern "C++" { 118 | 119 | class yyFlexLexer : public FlexLexer { 120 | public: 121 | // arg_yyin and arg_yyout default to the cin and cout, but we 122 | // only make that assignment when initializing in yylex(). 123 | yyFlexLexer( std::istream& arg_yyin, std::ostream& arg_yyout ); 124 | yyFlexLexer( std::istream* arg_yyin = 0, std::ostream* arg_yyout = 0 ); 125 | private: 126 | void ctor_common(); 127 | 128 | public: 129 | 130 | virtual ~yyFlexLexer(); 131 | 132 | void yy_switch_to_buffer( yy_buffer_state* new_buffer ); 133 | yy_buffer_state* yy_create_buffer( std::istream* s, int size ); 134 | yy_buffer_state* yy_create_buffer( std::istream& s, int size ); 135 | void yy_delete_buffer( yy_buffer_state* b ); 136 | void yyrestart( std::istream* s ); 137 | void yyrestart( std::istream& s ); 138 | 139 | void yypush_buffer_state( yy_buffer_state* new_buffer ); 140 | void yypop_buffer_state(); 141 | 142 | virtual int yylex(); 143 | virtual void switch_streams( std::istream& new_in, std::ostream& new_out ); 144 | virtual void switch_streams( std::istream* new_in = 0, std::ostream* new_out = 0 ); 145 | virtual int yywrap(); 146 | 147 | protected: 148 | virtual int LexerInput( char* buf, int max_size ); 149 | virtual void LexerOutput( const char* buf, int size ); 150 | virtual void LexerError( const char* msg ); 151 | 152 | void yyunput( int c, char* buf_ptr ); 153 | int yyinput(); 154 | 155 | void yy_load_buffer_state(); 156 | void yy_init_buffer( yy_buffer_state* b, std::istream& s ); 157 | void yy_flush_buffer( yy_buffer_state* b ); 158 | 159 | int yy_start_stack_ptr; 160 | int yy_start_stack_depth; 161 | int* yy_start_stack; 162 | 163 | void yy_push_state( int new_state ); 164 | void yy_pop_state(); 165 | int yy_top_state(); 166 | 167 | yy_state_type yy_get_previous_state(); 168 | yy_state_type yy_try_NUL_trans( yy_state_type current_state ); 169 | int yy_get_next_buffer(); 170 | 171 | std::istream yyin; // input source for default LexerInput 172 | std::ostream yyout; // output sink for default LexerOutput 173 | 174 | // yy_hold_char holds the character lost when yytext is formed. 175 | char yy_hold_char; 176 | 177 | // Number of characters read into yy_ch_buf. 178 | int yy_n_chars; 179 | 180 | // Points to current character in buffer. 181 | char* yy_c_buf_p; 182 | 183 | int yy_init; // whether we need to initialize 184 | int yy_start; // start state number 185 | 186 | // Flag which is used to allow yywrap()'s to do buffer switches 187 | // instead of setting up a fresh yyin. A bit of a hack ... 188 | int yy_did_buffer_switch_on_eof; 189 | 190 | 191 | size_t yy_buffer_stack_top; /**< index of top of stack. */ 192 | size_t yy_buffer_stack_max; /**< capacity of stack. */ 193 | yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */ 194 | void yyensure_buffer_stack(void); 195 | 196 | // The following are not always needed, but may be depending 197 | // on use of certain flex features (like REJECT or yymore()). 198 | 199 | yy_state_type yy_last_accepting_state; 200 | char* yy_last_accepting_cpos; 201 | 202 | yy_state_type* yy_state_buf; 203 | yy_state_type* yy_state_ptr; 204 | 205 | char* yy_full_match; 206 | int* yy_full_state; 207 | int yy_full_lp; 208 | 209 | int yy_lp; 210 | int yy_looking_for_trail_begin; 211 | 212 | int yy_more_flag; 213 | int yy_more_len; 214 | int yy_more_offset; 215 | int yy_prev_more_offset; 216 | }; 217 | 218 | } 219 | 220 | #endif // yyFlexLexer || ! yyFlexLexerOnce 221 | -------------------------------------------------------------------------------- /src/state/state.cpp: -------------------------------------------------------------------------------- 1 | #include "state.h" 2 | #include "compile/compiler.h" 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | 6 | namespace fakelua { 7 | 8 | state::state() { 9 | } 10 | 11 | state::~state() { 12 | } 13 | 14 | void state::compile_file(const std::string &filename, compile_config cfg) { 15 | LOG_INFO("start compile_file {}", filename); 16 | compiler c; 17 | auto result = c.compile_file(shared_from_this(), filename, cfg); 18 | LOG_INFO("compile_file {} ok ", filename); 19 | } 20 | 21 | void state::compile_string(const std::string &str, compile_config cfg) { 22 | LOG_INFO("start compile_string"); 23 | if (str.empty()) { 24 | return; 25 | } 26 | compiler c; 27 | auto result = c.compile_string(shared_from_this(), str, cfg); 28 | LOG_INFO("compile_string ok {}", result.file_name); 29 | } 30 | 31 | }// namespace fakelua 32 | -------------------------------------------------------------------------------- /src/state/state.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "jit/vm.h" 5 | #include "var_pool.h" 6 | #include "var_string_heap.h" 7 | #include "var_table_heap.h" 8 | 9 | namespace fakelua { 10 | 11 | // the state contains the running environment we need. 12 | class state : public fakelua_state { 13 | public: 14 | state(); 15 | 16 | virtual ~state(); 17 | 18 | virtual void compile_file(const std::string &filename, compile_config cfg) override; 19 | 20 | virtual void compile_string(const std::string &str, compile_config cfg) override; 21 | 22 | // call before running. this will reset the state. just for speed. 23 | void reset() { 24 | var_string_heap_.reset(); 25 | var_table_heap_.reset(); 26 | var_pool_.reset(); 27 | } 28 | 29 | var_string_heap &get_var_string_heap() { 30 | return var_string_heap_; 31 | } 32 | 33 | var_table_heap &get_var_table_heap() { 34 | return var_table_heap_; 35 | } 36 | 37 | var_pool &get_var_pool() { 38 | return var_pool_; 39 | } 40 | 41 | vm &get_vm() { 42 | return vm_; 43 | } 44 | 45 | private: 46 | var_string_heap var_string_heap_; 47 | var_table_heap var_table_heap_; 48 | var_pool var_pool_; 49 | vm vm_; 50 | }; 51 | 52 | }// namespace fakelua 53 | -------------------------------------------------------------------------------- /src/state/var_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "var_pool.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | 5 | namespace fakelua { 6 | 7 | var *var_pool::alloc() { 8 | if (next_var_index_ < vars_.size()) { 9 | auto ret = &vars_[next_var_index_]; 10 | next_var_index_++; 11 | return ret; 12 | } 13 | 14 | auto v = std::make_shared(); 15 | tmp_vars_.push_back(v); 16 | return v.get(); 17 | } 18 | 19 | void var_pool::reset() { 20 | next_var_index_ = 0; 21 | auto tmp_size = tmp_vars_.size(); 22 | tmp_vars_.clear(); 23 | 24 | if (tmp_size > 0) { 25 | vars_.resize(vars_.size() + tmp_size * 2); 26 | } 27 | } 28 | 29 | }// namespace fakelua 30 | -------------------------------------------------------------------------------- /src/state/var_pool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var/var.h" 6 | 7 | namespace fakelua { 8 | 9 | // every state has a var pool. 10 | // var_pool store all the vars used in the state. and not free the vars until the state is destroyed. 11 | class var_pool { 12 | public: 13 | var_pool() : tmp_vars_(0) { 14 | } 15 | 16 | ~var_pool() = default; 17 | 18 | // allocate a var with the type of nil. 19 | var *alloc(); 20 | 21 | // reset the var pool used index and check size. usually called before running. 22 | void reset(); 23 | 24 | private: 25 | // the vector stores the global vars. the length of the vector is the max we can use. 26 | // if next_var_index_ is equal to the length of the vector, we can't allocate more vars. 27 | // so we use tmp_vars_ to store the vars which are allocated temporarily. 28 | // and then we resize the vars_ to bigger size. 29 | std::vector vars_; 30 | 31 | // the index of the next var to be allocated. 32 | uint32_t next_var_index_ = 0; 33 | 34 | // the vector stores the pointers to the vars which are allocated temporarily. 35 | std::vector> tmp_vars_; 36 | }; 37 | 38 | }// namespace fakelua 39 | -------------------------------------------------------------------------------- /src/state/var_string_heap.cpp: -------------------------------------------------------------------------------- 1 | #include "var_string_heap.h" 2 | #include "fakelua.h" 3 | #include "state.h" 4 | #include "util/common.h" 5 | 6 | namespace fakelua { 7 | 8 | var_string *var_string_heap::alloc(const std::string_view &str, bool is_const) { 9 | // first, try to find the string in the const string map 10 | auto it = const_str_map_.find(str); 11 | if (it != const_str_map_.end()) { 12 | // found. return 13 | return it->second; 14 | } 15 | 16 | if (is_const) { 17 | // alloc const but found in tmp map, need to move it to const map 18 | it = tmp_str_map_.find(str); 19 | if (it != tmp_str_map_.end()) { 20 | // move it to const map 21 | auto s = it->second; 22 | tmp_str_map_.erase(it); 23 | const auto &key = s->str(); 24 | const_str_map_.emplace(key, s); 25 | return s; 26 | } 27 | 28 | // not found. 29 | auto s = var_string::make_var_string(str.data(), static_cast(str.size())); 30 | const auto &key = s->str(); 31 | const_str_map_.emplace(key, s); 32 | return s; 33 | } else { 34 | it = tmp_str_map_.find(str); 35 | if (it != tmp_str_map_.end()) { 36 | // found. 37 | return it->second; 38 | } 39 | 40 | // not found. 41 | auto s = var_string::make_var_string(str.data(), static_cast(str.size())); 42 | const auto &key = s->str(); 43 | tmp_str_map_.emplace(key, s); 44 | return s; 45 | } 46 | } 47 | 48 | void var_string_heap::reset() { 49 | for (auto &iter: const_str_map_) { 50 | free(iter.second); 51 | } 52 | const_str_map_.clear(); 53 | } 54 | 55 | }// namespace fakelua 56 | -------------------------------------------------------------------------------- /src/state/var_string_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var/var_string.h" 6 | 7 | namespace fakelua { 8 | 9 | // string heap hold all the string, string has two type: const string and tmp string. 10 | // const string allocated when compile function and global var. 11 | // tmp string allocated when running function, will clean up after each run. 12 | class var_string_heap { 13 | public: 14 | // alloc a string, and return the stored var_string. 15 | var_string *alloc(const std::string_view &str, bool is_const); 16 | 17 | // clear the string heap. usually called before running. 18 | void reset(); 19 | 20 | // get size 21 | size_t size() const { 22 | return const_str_map_.size() + tmp_str_map_.size(); 23 | } 24 | 25 | private: 26 | // the key is the input string_view, the value is the stored string 27 | std::unordered_map const_str_map_; 28 | std::unordered_map tmp_str_map_; 29 | }; 30 | 31 | }// namespace fakelua 32 | -------------------------------------------------------------------------------- /src/state/var_table_heap.cpp: -------------------------------------------------------------------------------- 1 | #include "var_table_heap.h" 2 | #include "state.h" 3 | #include "util/common.h" 4 | #include "var/var_table.h" 5 | 6 | namespace fakelua { 7 | 8 | var_table *var_table_heap::alloc(bool is_const) { 9 | auto t = new var_table(); 10 | if (is_const) { 11 | const_table_vec_.emplace_back(t); 12 | } else { 13 | tmp_table_vec_.emplace_back(t); 14 | } 15 | } 16 | 17 | void var_table_heap::reset() { 18 | for (auto &iter: tmp_table_vec_) { 19 | delete iter; 20 | } 21 | tmp_table_vec_.clear(); 22 | } 23 | 24 | }// namespace fakelua 25 | -------------------------------------------------------------------------------- /src/state/var_table_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var/var_string.h" 6 | 7 | namespace fakelua { 8 | 9 | class var_table; 10 | 11 | // table heap hold all the table, like string, it has two type: const table and tmp string. 12 | class var_table_heap { 13 | public: 14 | // alloc a table 15 | var_table *alloc(bool is_const); 16 | 17 | // clear the table heap. usually called before running. 18 | void reset(); 19 | 20 | // get size 21 | size_t size() const { 22 | return const_table_vec_.size() + tmp_table_vec_.size(); 23 | } 24 | 25 | private: 26 | // the key is the input string_view, the value is the stored string 27 | std::vector const_table_vec_; 28 | std::vector tmp_table_vec_; 29 | }; 30 | 31 | }// namespace fakelua 32 | -------------------------------------------------------------------------------- /src/util/call_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fakelua { 4 | 5 | class var; 6 | typedef var *(*VAR_FUNC)(...); 7 | 8 | inline var *call_var_func(VAR_FUNC func, const std::vector &args) { 9 | switch (args.size()) { 10 | case 0: 11 | return func(); 12 | case 1: 13 | return func(args[0]); 14 | case 2: 15 | return func(args[0], args[1]); 16 | case 3: 17 | return func(args[0], args[1], args[2]); 18 | case 4: 19 | return func(args[0], args[1], args[2], args[3]); 20 | case 5: 21 | return func(args[0], args[1], args[2], args[3], args[4]); 22 | case 6: 23 | return func(args[0], args[1], args[2], args[3], args[4], args[5]); 24 | case 7: 25 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); 26 | case 8: 27 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); 28 | case 9: 29 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); 30 | case 10: 31 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); 32 | case 11: 33 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); 34 | case 12: 35 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]); 36 | case 13: 37 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 38 | args[12]); 39 | case 14: 40 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 41 | args[12], args[13]); 42 | case 15: 43 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 44 | args[12], args[13], args[14]); 45 | case 16: 46 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 47 | args[12], args[13], args[14], args[15]); 48 | case 17: 49 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 50 | args[12], args[13], args[14], args[15], args[16]); 51 | case 18: 52 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 53 | args[12], args[13], args[14], args[15], args[16], args[17]); 54 | case 19: 55 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 56 | args[12], args[13], args[14], args[15], args[16], args[17], args[18]); 57 | case 20: 58 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 59 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19]); 60 | case 21: 61 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 62 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20]); 63 | case 22: 64 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 65 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21]); 66 | case 23: 67 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 68 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22]); 69 | case 24: 70 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 71 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 72 | args[23]); 73 | case 25: 74 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 75 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 76 | args[23], args[24]); 77 | case 26: 78 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 79 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 80 | args[23], args[24], args[25]); 81 | case 27: 82 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 83 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 84 | args[23], args[24], args[25], args[26]); 85 | case 28: 86 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 87 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 88 | args[23], args[24], args[25], args[26], args[27]); 89 | case 29: 90 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 91 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 92 | args[23], args[24], args[25], args[26], args[27], args[28]); 93 | case 30: 94 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 95 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 96 | args[23], args[24], args[25], args[26], args[27], args[28], args[29]); 97 | case 31: 98 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 99 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 100 | args[23], args[24], args[25], args[26], args[27], args[28], args[29], args[30]); 101 | case 32: 102 | return func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], 103 | args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], 104 | args[23], args[24], args[25], args[26], args[27], args[28], args[29], args[30], args[31]); 105 | default: 106 | throw_fakelua_exception(std::format("too many arguments: {}", args.size())); 107 | } 108 | } 109 | 110 | }// namespace fakelua 111 | -------------------------------------------------------------------------------- /src/util/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #ifndef _WIN32 55 | #include 56 | #endif 57 | 58 | #include "macro.h" 59 | #include "const_define.h" 60 | #include "debug.h" 61 | #include "exception.h" 62 | #include "logging.h" 63 | #include "magic_enum.hpp" 64 | #include "string_util.h" 65 | #include "call_helper.h" 66 | -------------------------------------------------------------------------------- /src/util/const_define.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fakelua { 4 | 5 | // var flag define 6 | static const int VAR_FLAG_CONST_IDX = 1; // const var, cannot be changed 7 | static const int VAR_FLAG_VARIADIC_IDX = 2;// variadic var, eg: ... in function(...) 8 | 9 | }// namespace fakelua 10 | -------------------------------------------------------------------------------- /src/util/debug.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | namespace fakelua { 4 | 5 | // a simple assert system, just use to debug. only work in mingw 6 | [[noreturn]] void debug_assert_fail(const std::string &str, const std::source_location &source) { 7 | throw_fakelua_exception(std::format("assert fail: {} at {}:{}:{}", str, source.file_name(), source.line(), source.column())); 8 | } 9 | 10 | }// namespace fakelua -------------------------------------------------------------------------------- /src/util/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace fakelua { 7 | 8 | // a simple assert system, just use to debug. only work in mingw 9 | [[noreturn]] void debug_assert_fail(const std::string &str, const std::source_location &source = std::source_location::current()); 10 | 11 | #ifdef _WIN32 12 | #define DEBUG_ASSERT(x) \ 13 | if (!(x)) { \ 14 | fakelua::debug_assert_fail(#x); \ 15 | } 16 | #else 17 | #define DEBUG_ASSERT(x) 18 | #endif 19 | 20 | }// namespace fakelua -------------------------------------------------------------------------------- /src/util/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "exception.h" 3 | 4 | namespace fakelua { 5 | 6 | // std::stacktrace::current() is not implemented in libstdc++ yet, so we have to use a fake one. 7 | std::string stacktrace_current() { 8 | std::string ret; 9 | #ifndef _WIN32 10 | ret.reserve(1024); 11 | ret += "stacktrace:\n"; 12 | void *buffer[1024]; 13 | int size = backtrace(buffer, 1024); 14 | char **strings = backtrace_symbols(buffer, size); 15 | for (int i = 0; i < size; ++i) { 16 | ret += strings[i]; 17 | ret += "\n"; 18 | } 19 | free(strings); 20 | #endif 21 | return ret; 22 | } 23 | 24 | [[noreturn]] void throw_fakelua_exception(const std::string &msg) { 25 | LOG_ERROR("fakelua error: {}\n{}", msg, stacktrace_current()); 26 | throw fakelua_exception(std::format("fakelua error: {}\n{}", msg, stacktrace_current())); 27 | } 28 | 29 | }// namespace fakelua 30 | -------------------------------------------------------------------------------- /src/util/exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fakelua { 4 | 5 | class fakelua_exception : public std::runtime_error { 6 | public: 7 | fakelua_exception(const std::string &msg) : std::runtime_error(msg) { 8 | } 9 | }; 10 | 11 | [[noreturn]] void throw_fakelua_exception(const std::string &msg); 12 | 13 | }// namespace fakelua 14 | -------------------------------------------------------------------------------- /src/util/file_util.cpp: -------------------------------------------------------------------------------- 1 | #include "file_util.h" 2 | #include "util/common.h" 3 | 4 | namespace fakelua { 5 | 6 | std::string generate_tmp_filename(const std::string &head, const std::string &tail) { 7 | auto tmpdir = std::filesystem::temp_directory_path(); 8 | tmpdir += std::filesystem::path::preferred_separator; 9 | tmpdir += "fakelua"; 10 | tmpdir += std::filesystem::path::preferred_separator; 11 | if (!std::filesystem::exists(tmpdir)) { 12 | std::filesystem::create_directories(tmpdir); 13 | } 14 | tmpdir += head; 15 | // create tmp file in system temp dir 16 | std::string fileName; 17 | std::srand(static_cast(std::time(nullptr))); 18 | do { 19 | fileName = tmpdir.string() + std::to_string(std::rand()) + tail; 20 | } while (std::ifstream(fileName)); 21 | return fileName; 22 | } 23 | 24 | }// namespace fakelua 25 | -------------------------------------------------------------------------------- /src/util/file_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | namespace fakelua { 6 | 7 | std::string generate_tmp_filename(const std::string &head, const std::string &tail); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/util/hash_func.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | 6 | typedef std::shared_ptr str_container_ptr; 7 | 8 | namespace std { 9 | template<> 10 | struct hash { 11 | size_t operator()(const str_container_ptr &k) const { 12 | return std::hash()(*k); 13 | } 14 | }; 15 | 16 | template<> 17 | struct equal_to { 18 | bool operator()(const str_container_ptr &k1, const str_container_ptr &k2) const { 19 | return *k1 == *k2; 20 | } 21 | }; 22 | 23 | }// namespace std 24 | 25 | namespace fakelua { 26 | 27 | template 28 | struct my_equal_to { 29 | bool operator()(const K1 &__x, const K2 &__y) const { 30 | return __x == __y; 31 | } 32 | }; 33 | 34 | template<> 35 | struct my_equal_to { 36 | bool operator()(const std::string &k1, const str_container_ptr &k2) const { 37 | return k1 == *k2; 38 | } 39 | }; 40 | 41 | template<> 42 | struct my_equal_to { 43 | bool operator()(const str_container_ptr &k1, const std::string &k2) const { 44 | return *k1 == k2; 45 | } 46 | }; 47 | 48 | template<> 49 | struct my_equal_to { 50 | bool operator()(const std::string_view &k1, const str_container_ptr &k2) const { 51 | return k1 == *k2; 52 | } 53 | }; 54 | 55 | template<> 56 | struct my_equal_to { 57 | bool operator()(const str_container_ptr &k1, const std::string_view &k2) const { 58 | return *k1 == k2; 59 | } 60 | }; 61 | 62 | }// namespace fakelua 63 | -------------------------------------------------------------------------------- /src/util/logging.cpp: -------------------------------------------------------------------------------- 1 | #include "logging.h" 2 | #include "common.h" 3 | 4 | namespace fakelua { 5 | 6 | log_level g_log_level = log_level::Error; 7 | 8 | void set_log_level(const log_level &level) { 9 | g_log_level = level; 10 | } 11 | 12 | bool check_log_level(const log_level &level) { 13 | return level <= g_log_level; 14 | } 15 | 16 | void log(const log_level &level, const std::string_view &message, const std::source_location &source) { 17 | auto tz = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}; 18 | std::string t = std::format("{:%F %T %Z}", tz); 19 | std::string s = std::format("{}:{}:{}", source.file_name(), source.line(), source.column()); 20 | std::string l = level == log_level::Error ? "ERROR" : "INFO"; 21 | auto line = std::format("[{}] {} | {} | {}", l, t, s, message); 22 | if (level == log_level::Error) { 23 | std::cerr << line << std::endl; 24 | } else { 25 | std::cout << line << std::endl; 26 | } 27 | } 28 | 29 | }// namespace fakelua 30 | -------------------------------------------------------------------------------- /src/util/logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace fakelua { 7 | 8 | // a simple logging system, just use to debug 9 | 10 | // log level 11 | enum class log_level { 12 | Off = 0, 13 | Error = 1, 14 | Info = 2, 15 | }; 16 | 17 | // set the log level, default is Error 18 | void set_log_level(const log_level &level); 19 | 20 | // check the log level, return true if the level is enabled 21 | bool check_log_level(const log_level &level); 22 | 23 | void log(const log_level &level, const std::string_view &message, const std::source_location &source = std::source_location::current()); 24 | 25 | #define LOG_INFO(fmt, ...) if (fakelua::check_log_level(fakelua::log_level::Info)) { fakelua::log(fakelua::log_level::Info, std::format(fmt, ##__VA_ARGS__), std::source_location::current()); } 26 | #define LOG_ERROR(fmt, ...) if (fakelua::check_log_level(fakelua::log_level::Error)) { fakelua::log(fakelua::log_level::Error, std::format(fmt, ##__VA_ARGS__), std::source_location::current()); } 27 | 28 | }// namespace fakelua 29 | -------------------------------------------------------------------------------- /src/util/macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fakelua { 4 | 5 | #define SET_FLAG_BIT(flag, pos, value) \ 6 | if (value) { \ 7 | flag |= (1 << (pos)); \ 8 | } else { \ 9 | flag &= ~(1 << (pos)); \ 10 | } 11 | 12 | #define GET_FLAG_BIT(flag, pos) ((flag >> (pos)) & 1) 13 | 14 | }// namespace fakelua 15 | -------------------------------------------------------------------------------- /src/util/string_util.cpp: -------------------------------------------------------------------------------- 1 | #include "string_util.h" 2 | 3 | namespace fakelua { 4 | 5 | /* 6 | \a: This displays an alarm bell symbol. 7 | \b or \\: These print a backslash in our string. 8 | \f: This is an escape sequence literal that is used to create a form feed. A form feed causes the cursor to move down to the next line without returning to the start of the line. 9 | \n: This is a very popular and commonly used sequence that creates new print lines. 10 | \r: This is a carriage return escape sequence. It moves the cursor to the beginning of the line without moving to the next line. 11 | \t: This creates a horizontal tab space. 12 | \v: This creates a vertical tab space. 13 | \": This allows us to insert double quotes in our string without special interpretation. 14 | \': This allows us to insert single quotes in our string without special interpretation. 15 | \z: zap following span of spaces 16 | \digit: read digits from buffer 17 | */ 18 | 19 | std::string replace_escape_chars(const std::string &str) { 20 | std::string result; 21 | for (std::string::const_iterator it = str.begin(); it != str.end();) { 22 | if (*it == '\\') { 23 | ++it; 24 | if (it == str.end()) { 25 | break; 26 | } 27 | switch (*it) { 28 | case 'a': 29 | result += '\a'; 30 | ++it; 31 | break; 32 | case 'b': 33 | result += '\b'; 34 | ++it; 35 | break; 36 | case '\\': 37 | result += '\\'; 38 | ++it; 39 | break; 40 | case 'f': 41 | result += '\f'; 42 | ++it; 43 | break; 44 | case 'n': 45 | result += '\n'; 46 | ++it; 47 | break; 48 | case 'r': 49 | result += '\r'; 50 | ++it; 51 | break; 52 | case 't': 53 | result += '\t'; 54 | ++it; 55 | break; 56 | case 'v': 57 | result += '\v'; 58 | ++it; 59 | break; 60 | case '\"': 61 | result += '\"'; 62 | ++it; 63 | break; 64 | case '\'': 65 | result += '\''; 66 | ++it; 67 | break; 68 | case 'z': 69 | // zap following span of spaces 70 | ++it; 71 | while (it != str.end() && *it == ' ') { 72 | ++it; 73 | } 74 | break; 75 | default: 76 | if (!isdigit(*it)) { 77 | throw_fakelua_exception(std::format("invalid escape sequence \\{}", *it)); 78 | } 79 | // read up to 3 digits 80 | int r = 0; /* result accumulator */ 81 | for (int i = 0; i < 3; ++i) { 82 | if (it == str.end() || !isdigit(*it)) { 83 | break; 84 | } 85 | r = 10 * r + *it - '0'; 86 | ++it; 87 | } 88 | if (r > 0xFF) { 89 | throw_fakelua_exception("decimal escape too large \\" + std::to_string(r)); 90 | } 91 | result += static_cast(r); 92 | break; 93 | } 94 | } else { 95 | result += *it; 96 | ++it; 97 | } 98 | } 99 | return result; 100 | } 101 | 102 | int64_t to_integer(const std::string_view &s) { 103 | int64_t result = 0; 104 | 105 | auto begin = s.begin(); 106 | auto base = 10; 107 | bool negative = false; 108 | if (s.length() > 1) { 109 | if (s[0] == '+') {//+123 110 | begin += 1; 111 | if (s.length() > 3 && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) {// +0x123 112 | begin += 2; 113 | base = 16; 114 | } 115 | } else if (s.length() > 2) { 116 | if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {// 0x123 117 | begin += 2; 118 | base = 16; 119 | } else if (s.length() > 3 && s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) {// -0x123 120 | begin += 3; 121 | base = 16; 122 | negative = true; 123 | } 124 | } 125 | } 126 | 127 | auto [ptr, ec] = std::from_chars(begin, s.data() + s.size(), result, base); 128 | if (ec == std::errc::invalid_argument) { 129 | throw_fakelua_exception(std::format("invalid argument: {}", s)); 130 | } else if (ec == std::errc::result_out_of_range) { 131 | throw_fakelua_exception(std::format("result out of range: {}", s)); 132 | } 133 | 134 | if (negative) { 135 | result = -result; 136 | } 137 | 138 | return result; 139 | } 140 | 141 | double to_float(const std::string_view &s) { 142 | double result = 0; 143 | 144 | auto begin = s.begin(); 145 | auto fmt = std::chars_format::general; 146 | bool negative = false; 147 | if (s.length() > 1) { 148 | if (s[0] == '+') {//+123 149 | begin += 1; 150 | if (s.length() > 3 && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) {// +0x123 151 | begin += 2; 152 | fmt = std::chars_format::hex; 153 | } 154 | } else if (s.length() > 2) { 155 | if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {// 0x123 156 | begin += 2; 157 | fmt = std::chars_format::hex; 158 | } else if (s.length() > 3 && s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) {// -0x123 159 | begin += 3; 160 | fmt = std::chars_format::hex; 161 | negative = true; 162 | } 163 | } 164 | } 165 | auto [ptr, ec] = std::from_chars(begin, s.data() + s.size(), result, fmt); 166 | if (ec == std::errc::invalid_argument) { 167 | throw_fakelua_exception(std::format("invalid argument: {}", s)); 168 | } else if (ec == std::errc::result_out_of_range) { 169 | throw_fakelua_exception(std::format("result out of range: {}", s)); 170 | } 171 | 172 | if (negative) { 173 | result = -result; 174 | } 175 | 176 | return result; 177 | } 178 | 179 | }// namespace fakelua 180 | -------------------------------------------------------------------------------- /src/util/string_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | namespace fakelua { 6 | 7 | // define the str_container_ptr 8 | typedef std::shared_ptr str_container_ptr; 9 | 10 | static const auto g_number_regex = 11 | std::regex("^[+-]?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$|^[+-]?0[xX][0-9a-fA-F]+(\\.[0-9a-fA-F]+)?([pP][+-]?[0-9]+)?$"); 12 | 13 | static const auto g_integer_regex = std::regex("^[+-]?[0-9]+$|^[+-]?0[xX][0-9a-fA-F]+$"); 14 | 15 | inline bool is_number(const std::string_view &s) { 16 | return std::regex_match(s.begin(), s.end(), g_number_regex); 17 | } 18 | 19 | inline bool is_integer(const std::string_view &s) { 20 | return std::regex_match(s.begin(), s.end(), g_integer_regex); 21 | } 22 | 23 | int64_t to_integer(const std::string_view &s); 24 | 25 | double to_float(const std::string_view &s); 26 | 27 | inline std::string join_string(const std::vector &strs, const std::string &sep) { 28 | return std::accumulate(std::next(strs.begin()), strs.end(), strs[0], 29 | [&](std::string a, std::string b) { return std::move(a) + sep + b; }); 30 | } 31 | 32 | std::string replace_escape_chars(const std::string &str); 33 | 34 | }// namespace fakelua 35 | -------------------------------------------------------------------------------- /src/var/var.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var_table.h" 6 | #include "var_type.h" 7 | 8 | namespace fakelua { 9 | 10 | class state; 11 | 12 | // Var is the class that holds the multiple types of data. 13 | class var { 14 | public: 15 | var() = default; 16 | 17 | explicit var(const bool b) { 18 | set_bool(b); 19 | } 20 | 21 | // get the var type 22 | [[nodiscard]] var_type type() const { 23 | return static_cast(type_); 24 | } 25 | 26 | // get bool value 27 | [[nodiscard]] bool get_bool() const { 28 | DEBUG_ASSERT(type_ == var_type::VAR_BOOL); 29 | return data_.b; 30 | } 31 | 32 | // get int value 33 | [[nodiscard]] int64_t get_int() const { 34 | DEBUG_ASSERT(type_ == var_type::VAR_INT); 35 | return data_.i; 36 | } 37 | 38 | // get float value 39 | [[nodiscard]] double get_float() const { 40 | DEBUG_ASSERT(type_ == var_type::VAR_FLOAT); 41 | return data_.f; 42 | } 43 | 44 | // get string_view value 45 | [[nodiscard]] var_string *get_string() const { 46 | DEBUG_ASSERT(type_ == var_type::VAR_STRING); 47 | return data_.s; 48 | } 49 | 50 | // get table value 51 | [[nodiscard]] var_table *get_table() const { 52 | DEBUG_ASSERT(type_ == var_type::VAR_TABLE); 53 | return data_.t; 54 | } 55 | 56 | public: 57 | // set nullptr 58 | void set_nil() { 59 | type_ = var_type::VAR_NIL; 60 | } 61 | 62 | // set bool value 63 | void set_bool(bool val) { 64 | type_ = var_type::VAR_BOOL; 65 | data_.b = val; 66 | } 67 | 68 | // set int value 69 | void set_int(int64_t val) { 70 | type_ = var_type::VAR_INT; 71 | data_.i = val; 72 | } 73 | 74 | // set float value 75 | void set_float(double val) { 76 | double intpart; 77 | if (std::modf(val, &intpart) != 0.0) { 78 | type_ = var_type::VAR_FLOAT; 79 | data_.f = val; 80 | } else { 81 | type_ = var_type::VAR_INT; 82 | data_.i = static_cast(val); 83 | } 84 | } 85 | 86 | // set string value 87 | void set_string(const fakelua_state_ptr &s, const std::string_view &val); 88 | 89 | // set string value 90 | void set_string(fakelua_state *s, const std::string_view &val); 91 | 92 | // set table value 93 | void set_table(fakelua_state *s); 94 | 95 | public: 96 | // to string 97 | [[nodiscard]] std::string to_string(bool has_quote = true, bool has_postfix = true) const; 98 | 99 | void set_const(bool val) { 100 | SET_FLAG_BIT(flag_, VAR_FLAG_CONST_IDX, val); 101 | } 102 | 103 | [[nodiscard]] bool is_const() const { 104 | return GET_FLAG_BIT(flag_, VAR_FLAG_CONST_IDX); 105 | } 106 | 107 | void set_variadic(bool val) { 108 | SET_FLAG_BIT(flag_, VAR_FLAG_VARIADIC_IDX, val); 109 | } 110 | 111 | [[nodiscard]] bool is_variadic() const { 112 | return GET_FLAG_BIT(flag_, VAR_FLAG_VARIADIC_IDX); 113 | } 114 | 115 | // get hash value 116 | [[nodiscard]] size_t hash() const; 117 | 118 | // equal 119 | [[nodiscard]] bool equal(const var &rhs) const; 120 | 121 | // is calculable 122 | [[nodiscard]] bool is_calculable() const; 123 | 124 | // is calculable integer 125 | [[nodiscard]] bool is_calculable_integer() const; 126 | 127 | // get calculable integer, only call this when is_calculable_integer() is true 128 | [[nodiscard]] int64_t get_calculable_int() const; 129 | 130 | // get calculable number value, maybe integer or float or string 131 | [[nodiscard]] double get_calculable_number() const; 132 | 133 | public: 134 | void plus(const var &rhs, var &result) const; 135 | 136 | void minus(const var &rhs, var &result) const; 137 | 138 | void star(const var &rhs, var &result) const; 139 | 140 | void slash(const var &rhs, var &result) const; 141 | 142 | void double_slash(const var &rhs, var &result) const; 143 | 144 | void pow(const var &rhs, var &result) const; 145 | 146 | void mod(const var &rhs, var &result) const; 147 | 148 | void bitand_(const var &rhs, var &result) const; 149 | 150 | void xor_(const var &rhs, var &result) const; 151 | 152 | void bitor_(const var &rhs, var &result) const; 153 | 154 | void right_shift(const var &rhs, var &result) const; 155 | 156 | void left_shift(const var &rhs, var &result) const; 157 | 158 | void concat(fakelua_state *s, const var &rhs, var &result) const; 159 | 160 | void less(const var &rhs, var &result) const; 161 | 162 | void less_equal(const var &rhs, var &result) const; 163 | 164 | void more(const var &rhs, var &result) const; 165 | 166 | void more_equal(const var &rhs, var &result) const; 167 | 168 | void equal(const var &rhs, var &result) const; 169 | 170 | void not_equal(const var &rhs, var &result) const; 171 | 172 | [[nodiscard]] bool test_true() const; 173 | 174 | void unop_minus(var &result) const; 175 | 176 | void unop_not(var &result) const; 177 | 178 | void unop_number_sign(var &result) const; 179 | 180 | void unop_bitnot(var &result) const; 181 | 182 | void table_set(var *key, var *val); 183 | 184 | const var *table_get(var *key) const; 185 | 186 | [[nodiscard]] size_t table_size() const; 187 | 188 | [[nodiscard]] const var *table_key_at(size_t pos) const; 189 | 190 | [[nodiscard]] const var *table_value_at(size_t pos) const; 191 | 192 | private: 193 | int type_ = var_type::VAR_NIL; 194 | int flag_ = 0; 195 | union data_ { 196 | bool b; 197 | int64_t i; 198 | double f; 199 | var_string *s; 200 | var_table *t; 201 | }; 202 | data_ data_{}; 203 | }; 204 | 205 | // assert var size is 16 bytes, the same as we defined in gccjit 206 | static_assert(sizeof(var) == 16); 207 | 208 | extern var const_null_var; 209 | extern var const_false_var; 210 | extern var const_true_var; 211 | 212 | }// namespace fakelua 213 | -------------------------------------------------------------------------------- /src/var/var_string.cpp: -------------------------------------------------------------------------------- 1 | #include "var_string.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | #include "var.h" 5 | 6 | namespace fakelua { 7 | 8 | 9 | }// namespace fakelua 10 | -------------------------------------------------------------------------------- /src/var/var_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var_type.h" 6 | 7 | namespace fakelua { 8 | 9 | // store the string data. use the plain memory to store the string data. 10 | class var_string { 11 | public: 12 | // make a var_string with the given data and size 13 | static var_string *make_var_string(const char *data, int size) { 14 | auto *s = static_cast(malloc(sizeof(var_string) + size)); 15 | s->size_ = size; 16 | memcpy((void *) s->data_, data, size); 17 | return s; 18 | } 19 | 20 | // return string view 21 | [[nodiscard]] const std::string_view &str() const { 22 | return {data_, static_cast(size_)}; 23 | } 24 | 25 | [[nodiscard]] size_t size() const { 26 | return static_cast(size_); 27 | } 28 | 29 | private: 30 | int size_ = 0; // size of the string 31 | const char data_[0];// data of the string 32 | }; 33 | 34 | // assert var_string header size is 4 bytes, the same as we defined in gccjit 35 | static_assert(sizeof(var_string) == 4, "var_string size must be 8 bytes"); 36 | 37 | }// namespace fakelua 38 | -------------------------------------------------------------------------------- /src/var/var_table.cpp: -------------------------------------------------------------------------------- 1 | #include "var_table.h" 2 | #include "fakelua.h" 3 | #include "util/common.h" 4 | #include "var.h" 5 | 6 | namespace fakelua { 7 | 8 | const var *var_table::get(var *key) const { 9 | DEBUG_ASSERT(key); 10 | DEBUG_ASSERT(key->type() >= var_type::VAR_MIN && key->type() <= var_type::VAR_MAX); 11 | for (const auto &it: table_) { 12 | if (it.first.equal(*key)) { 13 | return &it.second; 14 | } 15 | } 16 | return &const_null_var; 17 | } 18 | 19 | void var_table::set(const var *key, const var *val) { 20 | DEBUG_ASSERT(key); 21 | DEBUG_ASSERT(key->type() >= var_type::VAR_MIN && key->type() <= var_type::VAR_MAX); 22 | DEBUG_ASSERT(val); 23 | DEBUG_ASSERT(val->type() >= var_type::VAR_MIN && val->type() <= var_type::VAR_MAX); 24 | 25 | // set nil means delete 26 | if (val->type() == var_type::VAR_NIL) { 27 | for (size_t index = 0; index < table_.size(); ++index) { 28 | const auto &it = table_[index]; 29 | if (it.first.equal(*key)) { 30 | if (index < table_.size() - 1) { 31 | // swap with the last element 32 | table_[index] = table_.back(); 33 | } 34 | // pop back 35 | table_.pop_back(); 36 | break; 37 | } 38 | } 39 | return; 40 | } 41 | 42 | // find and update the value 43 | for (auto &it: table_) { 44 | if (it.first.equal(*key)) { 45 | it.second = *val; 46 | return; 47 | } 48 | } 49 | 50 | // not found, insert a new key-value pair 51 | table_.emplace_back(*key, *val); 52 | } 53 | 54 | const var *var_table::key_at(size_t pos) const { 55 | if (pos >= table_.size()) { 56 | return &const_null_var; 57 | } 58 | return &table_[pos].first; 59 | } 60 | 61 | const var *var_table::value_at(size_t pos) const { 62 | if (pos >= table_.size()) { 63 | return &const_null_var; 64 | } 65 | return &table_[pos].second; 66 | } 67 | 68 | }// namespace fakelua 69 | -------------------------------------------------------------------------------- /src/var/var_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | #include "var_type.h" 6 | 7 | namespace fakelua { 8 | 9 | class var; 10 | class var_string; 11 | 12 | // table type, like the lua table. but we implement it in a simple way. 13 | class var_table { 14 | public: 15 | // get value by key. if the key is not exist, return const var(nullptr). 16 | const var *get(var *key) const; 17 | 18 | // set value by key. if the key is not exist, insert a new key-value pair. 19 | void set(const var *key, const var *val); 20 | 21 | // get size 22 | size_t size() const { 23 | return table_.size(); 24 | } 25 | 26 | // get key at pos 27 | const var *key_at(size_t pos) const; 28 | 29 | // get value at pos 30 | const var *value_at(size_t pos) const; 31 | 32 | private: 33 | std::vector> table_; 34 | }; 35 | 36 | }// namespace fakelua 37 | -------------------------------------------------------------------------------- /src/var/var_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fakelua.h" 4 | #include "util/common.h" 5 | 6 | namespace fakelua { 7 | 8 | enum var_type { 9 | VAR_NIL, 10 | VAR_BOOL, 11 | VAR_INT, 12 | VAR_FLOAT, 13 | VAR_STRING, 14 | VAR_TABLE, 15 | }; 16 | 17 | #define VAR_MIN VAR_NIL 18 | #define VAR_MAX VAR_TABLE 19 | 20 | }// namespace fakelua 21 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | project(test) 4 | 5 | #add gtest 6 | CPMAddPackage( 7 | NAME googletest 8 | GITHUB_REPOSITORY google/googletest 9 | GIT_TAG v1.17.0 10 | VERSION 1.17.0 11 | OPTIONS 12 | "INSTALL_GTEST OFF" 13 | "gtest_force_shared_crt ON" 14 | ) 15 | 16 | include_directories(${magic_enum_SOURCE_DIR}/include/magic_enum) 17 | 18 | aux_source_directory(./ TEST_SRC_LIST) 19 | include_directories(./) 20 | include_directories(../include) 21 | include_directories(../src) 22 | include_directories(../src/platform) 23 | 24 | IF (WIN32) 25 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-all-symbols") 26 | ELSE () 27 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-E") 28 | ENDIF () 29 | 30 | add_executable(unit_tests ${TEST_SRC_LIST}) 31 | 32 | target_link_libraries(unit_tests PRIVATE fakelua gtest_main gccjit) 33 | 34 | add_test(NAME unit COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/unit_tests 35 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) 36 | 37 | add_custom_command( 38 | TARGET unit_tests 39 | POST_BUILD 40 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/lua/ ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/ 41 | ) 42 | -------------------------------------------------------------------------------- /test/lua/algo/fibonacci.lua: -------------------------------------------------------------------------------- 1 | local function fibonacci(n) 2 | if n <= 1 then 3 | return n 4 | else 5 | return fibonacci(n - 1) + fibonacci(n - 2) 6 | end 7 | end 8 | 9 | function test(n) 10 | return fibonacci(n) 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/exception/test_binop_plus_error.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local c = a + b 3 | return c 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_break_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | if a > 0 then 3 | break 4 | end 5 | return a 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_col_func_not_find_error.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = { test1 = "xxx" } } 2 | function _G.my:test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return _G.my:test1(a) 8 | end -------------------------------------------------------------------------------- /test/lua/exception/test_col_func_param_error.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = { } } 2 | function _G.my:test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return _G.my:test(a, a) 8 | end -------------------------------------------------------------------------------- /test/lua/exception/test_col_func_table_error.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = {} } 2 | function _G.my:test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return a:test(a) 8 | end -------------------------------------------------------------------------------- /test/lua/exception/test_col_func_type_error.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = { test1 = 2 } } 2 | function _G.my:test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return _G.my:test1(a) 8 | end -------------------------------------------------------------------------------- /test/lua/exception/test_compile_fail.lua: -------------------------------------------------------------------------------- 1 | function test( 2 | end 3 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_bitand_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "2" 3 | local c = a & b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_bitor_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "2" 3 | local c = a | b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_double_slash_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "a" 3 | local c = a // b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_left_shift_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "2" 3 | local c = a << b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_less_equal_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a <= b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_less_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a < b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_minus_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a - b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_mod_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a % b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_more_equal_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a >= b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_more_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a > b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_plus_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a + b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_pow_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = "a" 3 | local c = a ^ b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_right_shift_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "2" 3 | local c = a >> b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_slash_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "a" 3 | local c = a / b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_star_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "a" 3 | local c = a * b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_binop_xor_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local b = "2" 3 | local c = a ~ b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_define_duplicate.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local a = 2 3 | function test() 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_define_func_param_duplicate.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | function test(a) 3 | return a 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_define_no_match.lua: -------------------------------------------------------------------------------- 1 | local a, b = 1 2 | function test() 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_define_no_value.lua: -------------------------------------------------------------------------------- 1 | local a, b 2 | function test() 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_define_variadic.lua: -------------------------------------------------------------------------------- 1 | local a = ... 2 | function test() 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_func_call_error.lua: -------------------------------------------------------------------------------- 1 | local a = test() 2 | function test() 3 | return a 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_unop_bitnot_error.lua: -------------------------------------------------------------------------------- 1 | local a = "123" 2 | local c = ~a 3 | function test() 4 | return c 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_const_unop_len_error.lua: -------------------------------------------------------------------------------- 1 | local a = 1.2 2 | local c = #a 3 | function test() 4 | return c 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_exp_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x in pairs(a, a) do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_explist_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x in pairs(a), a do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_func_args_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y in pairs() do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_func_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y in mypair(a) do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_namelist_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y, z in pairs(a) do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_pairs_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y in a do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_prefix_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y in { } do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_for_in_prefix_func_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for x, y in pairs()() do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_function_call_exception.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | return a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_function_param_duplicate.lua: -------------------------------------------------------------------------------- 1 | function test(a, a) 2 | end 3 | -------------------------------------------------------------------------------- /test/lua/exception/test_function_param_local_duplicate.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local a = 1 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_global_duplicate_lvalue_error.lua: -------------------------------------------------------------------------------- 1 | local b = 1 2 | function test(a) 3 | local b = 2 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_label_exception.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | :: TEST :: 3 | local c = a + b 4 | return c 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_local_define_duplicate.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | local a 3 | local a 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_no_define_lvalue_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | b = 1 3 | return 1 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_return_type_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | return a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_stmt_support_error.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | goto label 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_table_get_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | return a[0] 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_table_loop_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | for k, v in pairs(a) do 3 | end 4 | return 1 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/exception/test_table_set_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | a[0] = 1 3 | return 1 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/exception/test_unop_minus_error.lua: -------------------------------------------------------------------------------- 1 | function test(a) 2 | return -a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/exception/test_variadic_function_call_exception.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, ...) 2 | return a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | a = 1 3 | b = "2" 4 | return a, b 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign_not_match.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | a, b = 1 3 | c, d = 3, 4, 5 4 | return a, b, c, d 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign_simple_var.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | a = b 3 | return a, b 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign_table_var.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local t = {} 3 | t[a] = b 4 | return t[a] 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign_variadic.lua: -------------------------------------------------------------------------------- 1 | function test(...) 2 | local a, b = ... 3 | return b, a 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_assign_variadic_no_match.lua: -------------------------------------------------------------------------------- 1 | function test(...) 2 | local a, b = ..., 1 3 | return b, a 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_and.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a and b 3 | local f = c and d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_and_bool.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return a and b, a or b 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_and_or.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = a and (b + 1) or (c + 1) 3 | local f = d and (b + 1) or (c + 1) 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_bitand.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a & b 3 | local f = c & d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_bitor.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a | b 3 | local f = c | d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_concat.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = a .. b .. c .. d 3 | return e 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_double_slash.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a // b 3 | local f = c // d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_equal.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a == b, c == d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_left_shift.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a << b 3 | local f = c << d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_less.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a < b, c < d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_less_equal.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a <= b, c <= d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_minus.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = a - b 3 | local f = c - d 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_mod.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a % b 3 | local f = c % d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_more.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a > b, c > d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_more_equal.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a >= b, c >= d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_not_equal.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e, f = a ~= b, c ~= d 3 | return e, f 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_or.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a or b 3 | local f = c or d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_plus.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = a + b 3 | local f = c + d 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_pow.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a ^ b 3 | local f = c ^ d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_right_shift.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a >> b 3 | local f = c >> d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_slash.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a / b 3 | local f = c / d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_star.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a * b 3 | local f = c * d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_binop_xor.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | local e = 2 + a ~ b 3 | local f = c ~ d - 1 4 | return e, f 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_and.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a and b 4 | local d = false 5 | local e = 2.2 6 | local f = d and e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_bitand.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3 3 | local c = a & b 4 | local d = "-123" 5 | local e = -124 6 | local f = d & e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_bitor.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3 3 | local c = a | b 4 | local d = "-123" 5 | local e = -124 6 | local f = d | e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_concat.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3.2 3 | local c = true 4 | local d = "abc" 5 | local e = nil 6 | local f = a .. b .. c .. d .. e 7 | function test() 8 | return f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_double_slash.lua: -------------------------------------------------------------------------------- 1 | local a = 3 2 | local b = 2 3 | local c = 1.2 + a // b 4 | local d = "2" 5 | local e = 1 6 | local f = d // e - 2.1 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_equal.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a == b 4 | local d = "2.2" 5 | local e = "2.2" 6 | local f = d == e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_left_shift.lua: -------------------------------------------------------------------------------- 1 | local a = 222 2 | local b = -3 3 | local c = a << b 4 | local d = "-124" 5 | local e = 2 6 | local f = d << e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_less.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a < b 4 | local d = "1.1" 5 | local e = 2.2 6 | local f = d < e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_less_equal.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a <= b 4 | local d = "2.2" 5 | local e = 2.2 6 | local f = d <= e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_minus.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = 2 3 | local c = a - b 4 | local d = 2.2 5 | local e = "1.1" 6 | local f = d - e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_mod.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3 3 | local c = a % b 4 | local d = "4.4" 5 | local e = 2.2 6 | local f = d % e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_more.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a > b 4 | local d = "1.1" 5 | local e = 2.2 6 | local f = d > e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_more_equal.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a >= b 4 | local d = "2.2" 5 | local e = 2.2 6 | local f = d >= e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_not_equal.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a ~= b 4 | local d = "2.2" 5 | local e = "2.2" 6 | local f = d ~= e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_or.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a or b 4 | local d = false 5 | local e = 2.2 6 | local f = d or e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_plus.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = 2 3 | local c = a + b 4 | local d = "1" 5 | local e = 2.2 6 | local f = d + e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_pow.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3 3 | local c = a ^ b 4 | local d = "1.1" 5 | local e = 2.2 6 | local f = d ^ e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_right_shift.lua: -------------------------------------------------------------------------------- 1 | local a = 222 2 | local b = -3 3 | local c = a >> b 4 | local d = "-123" 5 | local e = 2 6 | local f = d >> e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_slash.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = 2 3 | local c = 1.2 + a / b 4 | local d = "2.2" 5 | local e = 1 6 | local f = d / e - 2.1 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_star.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = 2 3 | local c = 1.2 + a * b 4 | local d = "1" 5 | local e = 2.2 6 | local f = d * e - 2.1 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_binop_xor.lua: -------------------------------------------------------------------------------- 1 | local a = 2 2 | local b = 3 3 | local c = a ~ b 4 | local d = "4" 5 | local e = 22 6 | local f = d ~ e 7 | function test() 8 | return c, f 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_define.lua: -------------------------------------------------------------------------------- 1 | local b = 1 2 | 3 | function test() 4 | return b 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_define_simple_var.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = a 3 | local c = b 4 | 5 | function test() 6 | return a, b, c 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_nested_table.lua: -------------------------------------------------------------------------------- 1 | local t = { 2 | array = { 1, 2, 3 }, 3 | map = { 4 | a = 1, 5 | b = 2, 6 | c = 3 7 | } 8 | } 9 | function test() 10 | return t 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_table.lua: -------------------------------------------------------------------------------- 1 | local t1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 2 | local t2 = { 3 | a = 1, 4 | b = 2, 5 | c = 3 6 | } 7 | local t3 = { 8 | 1, 9 | b = 2, 10 | 3, 11 | d = 4, 12 | 5 13 | } 14 | function test() 15 | return t1, t2, t3 16 | end 17 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_table_define.lua: -------------------------------------------------------------------------------- 1 | local c = { 2 | d = true, 3 | e = "2", 4 | f = { 5 | g = 1.23, 6 | h = { 1001, 1002, 1003 } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_unop_bitnot.lua: -------------------------------------------------------------------------------- 1 | local a = 123 2 | local b = -123 3 | local c = ~a 4 | local d = ~b 5 | function test() 6 | return c, d 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_unop_len.lua: -------------------------------------------------------------------------------- 1 | local a = "21" 2 | local b = { 1, 2, 3 } 3 | local c = #a 4 | local d = #b 5 | function test() 6 | return c, d 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_unop_minus.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = 3 3 | local c = a - -b 4 | function test() 5 | return c 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/jit/test_const_unop_not.lua: -------------------------------------------------------------------------------- 1 | local a = 21 2 | local b = false 3 | local c = not a 4 | local d = not b 5 | function test() 6 | return c, d 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_do_block.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | do 3 | a = 1 4 | b = "2" 5 | end 6 | return a, b 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_file.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esrrhs/fakelua/c4ac9428a68e4dcd741ac8d62d0faf494bb73789/test/lua/jit/test_empty_file.lua -------------------------------------------------------------------------------- /test/lua/jit/test_empty_func.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | return nil 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_func_call.lua: -------------------------------------------------------------------------------- 1 | local function inner() 2 | return 1 3 | end 4 | 5 | function test(a, b) 6 | return inner() 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_func_no_return.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | end 3 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_func_with_params.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, c, d) 2 | return d, c, b, a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_local_func.lua: -------------------------------------------------------------------------------- 1 | local function test() 2 | return nil -- even empty function must return value, because the translated cpp function has return value 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_empty_return.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | return 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, b, a, b, a } 4 | for k, v in pairs(map) do 5 | result = result + k + v 6 | end 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, a, a, a, a } 4 | for k, v in pairs(map) do 5 | for kk, vv in ipairs(map) do 6 | result = result + v + vv 7 | if result > b then 8 | break 9 | end 10 | end 11 | end 12 | return result 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_double.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, b, a, b, a } 4 | for k, v in pairs(map) do 5 | for kk, vv in ipairs(map) do 6 | result = result + k + v + kk + vv 7 | end 8 | end 9 | return result 10 | end 11 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_if_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, a, a, a, a } 4 | for k, v in pairs(map) do 5 | if v > b then 6 | result = b 7 | else 8 | return a 9 | end 10 | end 11 | return result 12 | end 13 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_just_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, a, a, a, a } 4 | for k, v in pairs(map) do 5 | result = v 6 | break 7 | end 8 | return result 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = { a, a } 4 | for k, v in pairs(map) do 5 | return v 6 | end 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_in_return_fallback.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | local map = {} 4 | for k, v in pairs(map) do 5 | return v 6 | end 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b, 2 do 4 | result = result + i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b, 2 do 4 | for j = 0, i do 5 | result = result + j + 1 6 | if result > 1 then 7 | break 8 | end 9 | end 10 | end 11 | return result 12 | end 13 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_default.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b do 4 | result = result + i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_double.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b, 2 do 4 | for j = 0, i do 5 | result = result + j 6 | end 7 | end 8 | return result 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_if_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b do 4 | if i > 5 then 5 | result = i 6 | else 7 | return i 8 | end 9 | end 10 | return result 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_just_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = a 3 | for i = a, b do 4 | result = b 5 | break 6 | end 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_for_loop_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = 0 3 | for i = a, b do 4 | return i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_global_func_call.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return inner(a, b) 3 | end 4 | 5 | function inner(a, b) 6 | return a >= b 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_if.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | if a > 4 and b > 4 then 3 | return 4 4 | elseif a > 3 or b > 3 then 5 | return 3 6 | else 7 | if a > 2 then 8 | return 2 9 | end 10 | end 11 | return 0 12 | end 13 | -------------------------------------------------------------------------------- /test/lua/jit/test_if_else.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | if a > 4 and b > 4 then 3 | return 4 4 | else 5 | return 0 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_if_elseif.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | if a > 4 and b > 4 then 3 | return 4 4 | elseif a > 3 or b > 3 then 5 | return 3 6 | elseif a > 2 or b > 2 then 7 | return 2 8 | elseif a > 1 or b > 1 then 9 | return 1 10 | end 11 | return 0 12 | end 13 | -------------------------------------------------------------------------------- /test/lua/jit/test_if_elseif_normal.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local ret = 0 3 | if a > 4 and b > 4 then 4 | ret = 4 5 | elseif a > 3 or b > 3 then 6 | ret = 3 7 | elseif a > 2 or b > 2 then 8 | ret = 2 9 | elseif a > 1 or b > 1 then 10 | ret = 1 11 | end 12 | return ret 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/jit/test_if_elseif_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local ret = 0 3 | if a > 4 and b > 4 then 4 | return 4 5 | elseif a > 3 or b > 3 then 6 | ret = 3 7 | elseif a > 2 or b > 2 then 8 | return 2 9 | elseif a > 1 or b > 1 then 10 | ret = 1 11 | end 12 | return ret 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/jit/test_if_simple.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | if a > 4 and b > 4 then 3 | return 4 4 | end 5 | return 0 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_define.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | local a 3 | local b 4 | return a, b 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_define_with_value.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local c, d, e = 1, "test" 3 | return a, b, c, d, e 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_func_call.lua: -------------------------------------------------------------------------------- 1 | local function inner(a, b) 2 | return a >= b 3 | end 4 | 5 | function test(a, b) 6 | return inner(a, b) 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_func_call_string.lua: -------------------------------------------------------------------------------- 1 | local function inner(t) 2 | return t.."_"..t 3 | end 4 | 5 | function test(a, b) 6 | return inner "test" 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_func_call_table_construct.lua: -------------------------------------------------------------------------------- 1 | local function inner(t) 2 | return t[1] >= t[2] 3 | end 4 | 5 | function test(a, b) 6 | return inner { a, b } 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_nested_table.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | local t = { 3 | array = { 1, 2, 3 }, 4 | map = { 5 | a = 1, 6 | b = 2, 7 | c = 3 8 | } 9 | } 10 | return t 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_table.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | local t1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 3 | local t2 = { 4 | a = 1, 5 | b = 2, 6 | c = 3 7 | } 8 | local t3 = { 9 | 1, 10 | b = 2, 11 | 3, 12 | d = 4, 13 | 5 14 | } 15 | return t1, t2, t3 16 | end 17 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_table_with_variadic.lua: -------------------------------------------------------------------------------- 1 | function test(...) 2 | local t = { 3 | ... 4 | } 5 | return t 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_table_with_variadic_no_end.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, ...) 2 | local t = { 3 | ..., 4 | a, 5 | b 6 | } 7 | return t 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_local_table_with_variadic_no_end_replace.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, ...) 2 | local t = { 3 | [1] = a, 4 | ..., 5 | b 6 | } 7 | return t 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_col_name_func.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = {} } 2 | function _G.my:test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return _G.my:test(a) 8 | end -------------------------------------------------------------------------------- /test/lua/jit/test_multi_const_define.lua: -------------------------------------------------------------------------------- 1 | local b0 = nil 2 | local b1 = 1 3 | local b2 = false 4 | local b3 = true 5 | local b4 = "test" 6 | local b5 = 2.3 7 | 8 | function test() 9 | return b0, b1, b2, b3, b4, b5 10 | end 11 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_name_func.lua: -------------------------------------------------------------------------------- 1 | local _G = { my = {} } 2 | function _G.my.test(a) 3 | return a + 1 4 | end 5 | 6 | function test(a) 7 | return _G.my.test(a) 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return.lua: -------------------------------------------------------------------------------- 1 | function test() 2 | return 1, 2.3, false, true, "test" 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return_call.lua: -------------------------------------------------------------------------------- 1 | local function test1() 2 | return 1, 2.3 3 | end 4 | 5 | local function test2(a, b, c) 6 | return a, b, c 7 | end 8 | 9 | function test() 10 | return test2("test", test1()) 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return_call_ex.lua: -------------------------------------------------------------------------------- 1 | local function test1() 2 | return 1, 2.3 3 | end 4 | 5 | local function test2(a, b, c) 6 | return a, b, c 7 | end 8 | 9 | function test() 10 | return test2("test", test1(), 2.4) 11 | end 12 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return_multi.lua: -------------------------------------------------------------------------------- 1 | function test1() 2 | return 3, 4, 5 3 | end 4 | 5 | function test() 6 | return 1, 2, test1() 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return_multi_ex.lua: -------------------------------------------------------------------------------- 1 | function test1() 2 | return 3, 4, 5 3 | end 4 | 5 | function test() 6 | return 1, 2, test1(), 6 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_multi_return_sub.lua: -------------------------------------------------------------------------------- 1 | local function test1() 2 | return "test", 1, 2.3 3 | end 4 | 5 | function test() 6 | local a, b, c = test1() 7 | return a, b, c 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | repeat 3 | a = a + 1 4 | b = b .. "2" 5 | until a >= 3 6 | return a, b 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local i = 1 3 | local result = 0 4 | repeat 5 | local j = 1 6 | repeat 7 | result = result + (i * j) 8 | if result > 5 then 9 | break 10 | end 11 | j = j + 1 12 | until j >= b 13 | i = i + 1 14 | until i >= a 15 | return result 16 | end 17 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat_double.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local i = 0 3 | local result = 0 4 | repeat 5 | local j = 0 6 | repeat 7 | result = result + (i * j) 8 | j = j + 1 9 | until j >= b 10 | i = i + 1 11 | until i >= a 12 | return result 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat_if_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | repeat 3 | if a > 5 then 4 | a = a+ 1 5 | else 6 | return a 7 | end 8 | until a > b 9 | return b 10 | end 11 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat_just_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = a 3 | repeat 4 | result = b 5 | break 6 | until a >= b 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_repeat_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | repeat 3 | return a 4 | until a > 0 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_table_get_set.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local t = { tt = { ttt = a } } 3 | t.tt.ttt = t.tt.ttt + b 4 | return t.tt.ttt 5 | end 6 | -------------------------------------------------------------------------------- /test/lua/jit/test_table_var_func_call.lua: -------------------------------------------------------------------------------- 1 | function inner(a, b) 2 | return a >= b 3 | end 4 | 5 | function test(a, b) 6 | local c = { "inner" } 7 | return c[1](a, b) 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_unop_bitnot.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return ~a, ~b 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_unop_len.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return #a, #b 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_unop_minus.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return 1 - -a * -b 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_unop_not.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | return not a, not b 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_var_func_call.lua: -------------------------------------------------------------------------------- 1 | function inner(a, b) 2 | return a >= b 3 | end 4 | 5 | function test(a, b) 6 | local c = "inner" 7 | return c(a, b) 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_variadic_func.lua: -------------------------------------------------------------------------------- 1 | function test(...) 2 | return ... 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_variadic_func_with_params.lua: -------------------------------------------------------------------------------- 1 | function test(a, b, ...) 2 | return ..., b, a 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/jit/test_while.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | while a < 3 do 3 | a = a + 1 4 | b = b .. "2" 5 | end 6 | return a, b 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/jit/test_while_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local i = 1 3 | local result = 0 4 | while i < a do 5 | local j = 1 6 | while j < b do 7 | result = result + (i * j) 8 | if result > 5 then 9 | break 10 | end 11 | j = j + 1 12 | end 13 | i = i + 1 14 | end 15 | return result 16 | end 17 | -------------------------------------------------------------------------------- /test/lua/jit/test_while_double.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local i = 0 3 | local result = 0 4 | while i < a do 5 | local j = 0 6 | while j < b do 7 | result = result + (i * j) 8 | j = j + 1 9 | end 10 | i = i + 1 11 | end 12 | return result 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/jit/test_while_if_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | while a < b do 3 | if a > 5 then 4 | a = a + 1 5 | else 6 | return a 7 | end 8 | end 9 | return b 10 | end 11 | -------------------------------------------------------------------------------- /test/lua/jit/test_while_just_break.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | local result = a 3 | while a < b do 4 | result = b 5 | break 6 | end 7 | return result 8 | end 9 | -------------------------------------------------------------------------------- /test/lua/jit/test_while_return.lua: -------------------------------------------------------------------------------- 1 | function test(a, b) 2 | while a < 3 do 3 | return a 4 | end 5 | return b 6 | end 7 | -------------------------------------------------------------------------------- /test/lua/syntax/test_assign.lua: -------------------------------------------------------------------------------- 1 | -- assign 2 | a, b[2], c.d = nil, {}, e + f 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_assign_simple.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[ 3 | this is multi line comment 4 | --]] 5 | 6 | a = 1 -- this is a comment -------------------------------------------------------------------------------- /test/lua/syntax/test_binop.lua: -------------------------------------------------------------------------------- 1 | 2 | a = (b ^ c) ~ d -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order1.lua: -------------------------------------------------------------------------------- 1 | 2 | a = b / 2 + 1 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order2.lua: -------------------------------------------------------------------------------- 1 | 2 | a = a + i < b / 2 + 1 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order3.lua: -------------------------------------------------------------------------------- 1 | 2 | a = 5 + x ^ 2 * 8 -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order4.lua: -------------------------------------------------------------------------------- 1 | 2 | a = a < y and y <= z -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order5.lua: -------------------------------------------------------------------------------- 1 | a=-x^2 -------------------------------------------------------------------------------- /test/lua/syntax/test_binop_order6.lua: -------------------------------------------------------------------------------- 1 | a=x^y^z -------------------------------------------------------------------------------- /test/lua/syntax/test_break.lua: -------------------------------------------------------------------------------- 1 | 2 | while true do 3 | break 4 | end 5 | -------------------------------------------------------------------------------- /test/lua/syntax/test_constructor.lua: -------------------------------------------------------------------------------- 1 | 2 | a = { 3 | [2] = 1, 4 | a = 2 5 | } 6 | -------------------------------------------------------------------------------- /test/lua/syntax/test_continue.lua: -------------------------------------------------------------------------------- 1 | local a = { b = 1, c = "2" } 2 | goto continue 3 | :: continue :: 4 | -------------------------------------------------------------------------------- /test/lua/syntax/test_do_end.lua: -------------------------------------------------------------------------------- 1 | do local a = b.c or {} end -------------------------------------------------------------------------------- /test/lua/syntax/test_empty.lua: -------------------------------------------------------------------------------- 1 | ; 2 | ; 3 | ; -------------------------------------------------------------------------------- /test/lua/syntax/test_for_in.lua: -------------------------------------------------------------------------------- 1 | for key, value in pairs(data) do 2 | print(key, value) 3 | end 4 | 5 | for key in pairs(data) do 6 | data[key] = nil 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/syntax/test_for_num.lua: -------------------------------------------------------------------------------- 1 | for n = 1, 10 do 2 | print(n) 3 | end 4 | 5 | for m = ini(), max, 2 do 6 | print(n) 7 | end 8 | -------------------------------------------------------------------------------- /test/lua/syntax/test_function.lua: -------------------------------------------------------------------------------- 1 | function func_a() 2 | end 3 | 4 | function _G.a.b:func_b(a, b, c, ...) 5 | return a + b + c 6 | end 7 | 8 | local function func_c(...) 9 | local param_list = {...} 10 | for i = 1, #param_list do 11 | print(param_list[i]) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /test/lua/syntax/test_function_call.lua: -------------------------------------------------------------------------------- 1 | 2 | a.b[1].func_a(a,b,c):func_c() 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_function_call_args.lua: -------------------------------------------------------------------------------- 1 | 2 | a {b=1} 3 | c "d" 4 | -------------------------------------------------------------------------------- /test/lua/syntax/test_function_exp.lua: -------------------------------------------------------------------------------- 1 | 2 | a = function(b) 3 | end 4 | -------------------------------------------------------------------------------- /test/lua/syntax/test_if.lua: -------------------------------------------------------------------------------- 1 | if (self.methods.init) then 2 | if (tostring(arg[1]) ~= "___CREATE_ONLY___") then 3 | obj:init(unpack(arg)) 4 | else 5 | obj.___CREATE_ONLY___ = true 6 | end 7 | elseif (tostring(arg[1]) ~= "___CREATE_ONLY___") then 8 | error("No init method found for class " .. self.name) 9 | end 10 | -------------------------------------------------------------------------------- /test/lua/syntax/test_label.lua: -------------------------------------------------------------------------------- 1 | 2 | ::aa:: 3 | 4 | ::bb:: 5 | -------------------------------------------------------------------------------- /test/lua/syntax/test_number.lua: -------------------------------------------------------------------------------- 1 | a=1 2 | b=true 3 | c=false 4 | d=nil 5 | e=1.123 6 | f=-2.234 7 | g=1.1e10 8 | h=-1.1e-10 9 | i=0xff 10 | j=0x1e.ff 11 | k=-0x3.1ap-4 12 | -------------------------------------------------------------------------------- /test/lua/syntax/test_repeat.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | n = n + 1 3 | until n == 0 -------------------------------------------------------------------------------- /test/lua/syntax/test_string.lua: -------------------------------------------------------------------------------- 1 | a = "a" 2 | b = 'b' 3 | c = "'c'" 4 | d = '"d"' 5 | e = "\"e\"" 6 | f = '\'f\'' 7 | g = [[g 8 | g]] -------------------------------------------------------------------------------- /test/lua/syntax/test_var.lua: -------------------------------------------------------------------------------- 1 | local any 2 | local a, b, c = 1, "2", func() 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_var_attr.lua: -------------------------------------------------------------------------------- 1 | local any 2 | local a, b , c = 1, "2", func() 3 | -------------------------------------------------------------------------------- /test/lua/syntax/test_while.lua: -------------------------------------------------------------------------------- 1 | 2 | while not loop() do 3 | end 4 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "fakelua.h" 2 | #include "util/common.h" 3 | #include "gtest/gtest.h" 4 | 5 | int main(int argc, char **argv) { 6 | testing::InitGoogleTest(&argc, argv); 7 | return RUN_ALL_TESTS(); 8 | } 9 | -------------------------------------------------------------------------------- /test/test_algo.cpp: -------------------------------------------------------------------------------- 1 | #include "compile/compiler.h" 2 | #include "fakelua.h" 3 | #include "gtest/gtest.h" 4 | 5 | using namespace fakelua; 6 | 7 | TEST(algo, fibonacci) { 8 | auto L = fakelua_newstate(); 9 | ASSERT_NE(L.get(), nullptr); 10 | 11 | int i = 0; 12 | L->compile_file("./algo/fibonacci.lua", {}); 13 | L->call("test", std::tie(i), 30); 14 | ASSERT_EQ(i, 832040); 15 | 16 | i = 0; 17 | L->compile_file("./algo/fibonacci.lua", {.debug_mode = false}); 18 | L->call("test", std::tie(i), 30); 19 | ASSERT_EQ(i, 832040); 20 | } 21 | -------------------------------------------------------------------------------- /test/test_common.cpp: -------------------------------------------------------------------------------- 1 | #include "fakelua.h" 2 | #include "util/common.h" 3 | #include "util/string_util.h" 4 | #include "gtest/gtest.h" 5 | 6 | using namespace fakelua; 7 | 8 | TEST(common, escapse_string) { 9 | std::string src = "a\\ab\\bc\\fd\\ne\\rf\\tg\\vh\\\"i\\'j\\\\k"; 10 | std::string dst = replace_escape_chars(src); 11 | ASSERT_EQ(dst, "a\ab\bc\fd\ne\rf\tg\vh\"i\'j\\k"); 12 | 13 | src = "\\a\\b\\f\\n\\r\\t\\v\\\"\\'"; 14 | dst = replace_escape_chars(src); 15 | ASSERT_EQ(dst, "\a\b\f\n\r\t\v\"\'"); 16 | 17 | src = "a\\z b"; 18 | dst = replace_escape_chars(src); 19 | ASSERT_EQ(dst, "ab"); 20 | 21 | src = "a\\z "; 22 | dst = replace_escape_chars(src); 23 | ASSERT_EQ(dst, "a"); 24 | 25 | src = "\\z \\z "; 26 | dst = replace_escape_chars(src); 27 | ASSERT_EQ(dst, ""); 28 | 29 | src = "\\z\\z "; 30 | dst = replace_escape_chars(src); 31 | ASSERT_EQ(dst, ""); 32 | 33 | src = "\\z\\z"; 34 | dst = replace_escape_chars(src); 35 | ASSERT_EQ(dst, ""); 36 | 37 | src = "a\\97b"; 38 | dst = replace_escape_chars(src); 39 | ASSERT_EQ(dst, "aab"); 40 | 41 | src = "a\\97"; 42 | dst = replace_escape_chars(src); 43 | ASSERT_EQ(dst, "aa"); 44 | 45 | src = "\\097b"; 46 | dst = replace_escape_chars(src); 47 | ASSERT_EQ(dst, "ab"); 48 | 49 | src = "\\097\\97"; 50 | dst = replace_escape_chars(src); 51 | ASSERT_EQ(dst, "aa"); 52 | } 53 | 54 | TEST(common, logging) { 55 | set_log_level(log_level::Info); 56 | LOG_INFO("Hello, World!"); 57 | LOG_ERROR("Hello, World!"); 58 | } 59 | 60 | TEST(common, vi_sort) { 61 | simple_var_impl t; 62 | std::vector> kv; 63 | 64 | simple_var_impl k1; 65 | k1.vi_set_nil(); 66 | simple_var_impl v1; 67 | v1.vi_set_int(1); 68 | kv.push_back(std::make_pair(&k1, &v1)); 69 | 70 | simple_var_impl k2; 71 | k2.vi_set_nil(); 72 | simple_var_impl v2; 73 | v2.vi_set_int(1); 74 | kv.push_back(std::make_pair(&k2, &v2)); 75 | 76 | simple_var_impl k3; 77 | k3.vi_set_bool(true); 78 | simple_var_impl v3; 79 | v3.vi_set_int(3); 80 | kv.push_back(std::make_pair(&k3, &v3)); 81 | 82 | simple_var_impl k4; 83 | k4.vi_set_bool(false); 84 | simple_var_impl v4; 85 | v4.vi_set_int(4); 86 | kv.push_back(std::make_pair(&k4, &v4)); 87 | 88 | simple_var_impl k5; 89 | k5.vi_set_float(1.0); 90 | simple_var_impl v5; 91 | v5.vi_set_int(5); 92 | kv.push_back(std::make_pair(&k5, &v5)); 93 | 94 | simple_var_impl k6; 95 | k6.vi_set_float(2.0); 96 | simple_var_impl v6; 97 | v6.vi_set_int(6); 98 | kv.push_back(std::make_pair(&k6, &v6)); 99 | 100 | simple_var_impl k7; 101 | k7.vi_set_table({}); 102 | simple_var_impl v7; 103 | v7.vi_set_int(7); 104 | kv.push_back(std::make_pair(&k7, &v7)); 105 | 106 | simple_var_impl k8; 107 | k8.vi_set_table({}); 108 | simple_var_impl v8; 109 | v8.vi_set_int(7); 110 | kv.push_back(std::make_pair(&k8, &v8)); 111 | 112 | shuffle(kv.begin(), kv.end(), std::mt19937(std::random_device()())); 113 | 114 | t.vi_set_table(kv); 115 | t.vi_sort_table(); 116 | 117 | ASSERT_EQ(t.vi_to_string(), "table:\n\t[nil] = 1\n\t[nil] = 1\n\t[false] = 4\n\t[true] = 3\n\t[1.000000] = 5\n\t[2.000000] = " 118 | "6\n\t[table:] = 7\n\t[table:] = 7"); 119 | } 120 | 121 | TEST(common, is_number) { 122 | ASSERT_TRUE(is_number("123")); 123 | ASSERT_TRUE(is_number("-123")); 124 | ASSERT_TRUE(is_number("+123")); 125 | 126 | ASSERT_TRUE(is_number("123.456")); 127 | ASSERT_TRUE(is_number("-123.456")); 128 | ASSERT_TRUE(is_number("+123.456")); 129 | 130 | ASSERT_TRUE(is_number("123e456")); 131 | ASSERT_TRUE(is_number("-123e-456")); 132 | ASSERT_TRUE(is_number("+123E+456")); 133 | 134 | ASSERT_TRUE(is_number("0x123")); 135 | ASSERT_TRUE(is_number("-0X123")); 136 | ASSERT_TRUE(is_number("+0x123.456")); 137 | ASSERT_TRUE(is_number("-0X123.456P+789")); 138 | 139 | ASSERT_FALSE(is_number("abc")); 140 | ASSERT_FALSE(is_number("123abc")); 141 | ASSERT_FALSE(is_number("123.456.789")); 142 | } 143 | 144 | TEST(common, is_integer) { 145 | ASSERT_TRUE(is_integer("123")); 146 | ASSERT_TRUE(is_integer("-123")); 147 | ASSERT_TRUE(is_integer("+123")); 148 | 149 | ASSERT_TRUE(is_integer("0x123")); 150 | ASSERT_TRUE(is_integer("-0X123")); 151 | 152 | ASSERT_FALSE(is_integer("123.456")); 153 | ASSERT_FALSE(is_integer("-123.456")); 154 | ASSERT_FALSE(is_integer("+123.456")); 155 | ASSERT_FALSE(is_integer("123e456")); 156 | ASSERT_FALSE(is_integer("-123e-456")); 157 | ASSERT_FALSE(is_integer("+123E+456")); 158 | ASSERT_FALSE(is_integer("+0x123.456")); 159 | ASSERT_FALSE(is_integer("-0X123.456P+789")); 160 | ASSERT_FALSE(is_integer("abc")); 161 | ASSERT_FALSE(is_integer("123abc")); 162 | ASSERT_FALSE(is_integer("123.456.789")); 163 | } 164 | 165 | TEST(common, to_integer) { 166 | ASSERT_EQ(to_integer("123"), 123); 167 | ASSERT_EQ(to_integer("-123"), -123); 168 | ASSERT_EQ(to_integer("+123"), 123); 169 | ASSERT_EQ(to_integer("0x123"), 0x123); 170 | ASSERT_EQ(to_integer("0X123"), 0x123); 171 | ASSERT_EQ(to_integer("+0X123"), 0x123); 172 | ASSERT_EQ(to_integer("-0X123"), -0x123); 173 | 174 | ASSERT_EQ(to_integer("0"), 0); 175 | ASSERT_EQ(to_integer("-0"), 0); 176 | ASSERT_EQ(to_integer("0x0"), 0); 177 | ASSERT_EQ(to_integer("0X0"), 0); 178 | 179 | ASSERT_EQ(to_integer("9223372036854775807"), INT64_MAX); 180 | ASSERT_EQ(to_integer("-9223372036854775808"), INT64_MIN); 181 | 182 | ASSERT_EQ(to_integer("0xff"), 255); 183 | ASSERT_EQ(to_integer("0xBEBADA"), 0xBEBADA); 184 | } 185 | 186 | TEST(common, to_float) { 187 | ASSERT_TRUE(std::isnan(to_float("nan"))); 188 | ASSERT_TRUE(std::isnan(to_float("NaN"))); 189 | ASSERT_TRUE(std::isnan(to_float("NAN"))); 190 | ASSERT_TRUE(std::isinf(to_float("inf"))); 191 | ASSERT_TRUE(std::isinf(to_float("Inf"))); 192 | ASSERT_TRUE(std::isinf(to_float("INF"))); 193 | ASSERT_TRUE(std::isinf(to_float("-inf"))); 194 | ASSERT_TRUE(std::isinf(to_float("-Inf"))); 195 | ASSERT_TRUE(std::isinf(to_float("-INF"))); 196 | 197 | ASSERT_EQ(to_float("0"), 0); 198 | 199 | ASSERT_EQ(to_float("12.3"), 12.3); 200 | ASSERT_EQ(to_float("-12.3"), -12.3); 201 | ASSERT_EQ(to_float("+12.3"), 12.3); 202 | 203 | ASSERT_EQ(to_float("12.3e45"), 12.3e45); 204 | ASSERT_EQ(to_float("12.3e+45"), 12.3e+45); 205 | ASSERT_EQ(to_float("-12.3e-45"), -12.3e-45); 206 | 207 | ASSERT_EQ(to_float("0x123"), 0x123); 208 | ASSERT_EQ(to_float("0X12.3"), 18.1875); 209 | ASSERT_EQ(to_float("0X12.3P45"), 18.1875 * std::pow(2, 45)); 210 | ASSERT_EQ(to_float("0X12.3P+45"), 18.1875 * std::pow(2, 45)); 211 | ASSERT_EQ(to_float("0X12.3P-45"), 18.1875 * std::pow(2, -45)); 212 | ASSERT_EQ(to_float("0X12.3P+0"), 18.1875); 213 | 214 | ASSERT_EQ(to_float("+0x123"), 0x123); 215 | ASSERT_EQ(to_float("+0X12.3"), 18.1875); 216 | ASSERT_EQ(to_float("+0X12.3P45"), 18.1875 * std::pow(2, 45)); 217 | ASSERT_EQ(to_float("+0X12.3P+45"), 18.1875 * std::pow(2, 45)); 218 | ASSERT_EQ(to_float("+0X12.3P-45"), 18.1875 * std::pow(2, -45)); 219 | ASSERT_EQ(to_float("+0X12.3P+0"), 18.1875); 220 | 221 | ASSERT_EQ(to_float("-0x123"), -0x123); 222 | ASSERT_EQ(to_float("-0X12.3"), -18.1875); 223 | ASSERT_EQ(to_float("-0X12.3P45"), -18.1875 * std::pow(2, 45)); 224 | ASSERT_EQ(to_float("-0X12.3P+45"), -18.1875 * std::pow(2, 45)); 225 | ASSERT_EQ(to_float("-0X12.3P-45"), -18.1875 * std::pow(2, -45)); 226 | ASSERT_EQ(to_float("-0X12.3P+0"), -18.1875); 227 | 228 | ASSERT_EQ(to_float("1.7976931348623157e+308"), std::numeric_limits::max()); 229 | ASSERT_EQ(to_float("2.2250738585072014e-308"), std::numeric_limits::min()); 230 | 231 | ASSERT_EQ(to_float("3.1416"), 3.1416); 232 | ASSERT_EQ(to_float("314.16e-2"), 314.16e-2); 233 | ASSERT_EQ(to_float("0.31416E1"), 0.31416E1); 234 | ASSERT_EQ(to_float("34e1"), 34e1); 235 | ASSERT_EQ(to_float("0x0.1E"), 0.1171875); 236 | ASSERT_EQ(to_float("0xA23p-4"), 0xA23p-4); 237 | ASSERT_EQ(to_float("0X1.921FB54442D18P+1"), 0X1.921FB54442D18P+1); 238 | } 239 | -------------------------------------------------------------------------------- /test/test_ini.cpp: -------------------------------------------------------------------------------- 1 | #include "fakelua.h" 2 | #include "gtest/gtest.h" 3 | 4 | using namespace fakelua; 5 | 6 | TEST(ini, newstate) { 7 | auto L = fakelua_newstate(); 8 | ASSERT_NE(L.get(), nullptr); 9 | } 10 | --------------------------------------------------------------------------------