├── .cpack_ignore ├── .github ├── FUNDING.yml └── workflows │ ├── macos-build-extensions.yml │ ├── macos-build.yml │ ├── macos-release.yml │ ├── ubuntu-build-extensions.yml │ ├── ubuntu-build.yml │ ├── ubuntu-release.yml │ ├── windows-build.yml │ └── windows-release.yml ├── .gitignore ├── AUTHORS ├── BUILDING.md ├── CHANGELOG.md ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── benchmark ├── fib.hk ├── fib.js ├── fib.lua ├── fib.php ├── fib.py └── fib.rb ├── cli ├── CMakeLists.txt └── main.c ├── codecov.yml ├── core ├── CMakeLists.txt ├── arrays.c ├── arrays.h ├── deps │ ├── ascii85.c │ ├── ascii85.h │ ├── base32.c │ ├── base32.h │ ├── base58.c │ ├── base58.h │ ├── base64.c │ ├── base64.h │ ├── cJSON.c │ ├── cJSON.h │ ├── crc32.c │ ├── crc32.h │ ├── crc64.c │ ├── crc64.h │ ├── ini.c │ ├── ini.h │ ├── md5.c │ ├── md5.h │ ├── ripemd160.c │ ├── ripemd160.h │ ├── sha1.c │ ├── sha1.h │ ├── sha2.c │ ├── sha2.h │ ├── sha3.c │ └── sha3.h ├── encoding.c ├── encoding.h ├── hashing.c ├── hashing.h ├── ini.c ├── ini.h ├── io.c ├── io.h ├── json.c ├── json.h ├── lists.c ├── lists.h ├── math.c ├── math.h ├── numbers.c ├── numbers.h ├── os.c ├── os.h ├── selectors.c ├── selectors.h ├── socket.c ├── socket.h ├── strings.c ├── strings.h ├── utf8.c └── utf8.h ├── disabled-workflows ├── build-with-extensions.yml └── release-with-extensions.yml ├── docs ├── built-in.md ├── built-in.txt ├── core-modules.md ├── core-modules.txt ├── grammar.ebnf ├── grammar.md ├── keywords.txt ├── opcodes.txt └── tokens.txt ├── examples ├── 100doors.hk ├── 99bottles.hk ├── ackermann.hk ├── bigint.hk ├── binary_search.hk ├── bubble_sort.hk ├── closure.hk ├── coin_flip.hk ├── collatz.hk ├── curl.hk ├── distance.hk ├── ecdsa.hk ├── factorial.hk ├── fibonacci.hk ├── fizzbuzz.hk ├── fractal.hk ├── guessing_game.hk ├── hailstone.hk ├── hanoi.hk ├── hello.hk ├── import.hk ├── json.hk ├── knapsack.hk ├── knuth_shuffle.hk ├── mandelbrot.hk ├── module.hk ├── nbody.hk ├── num_to_words.hk ├── palindrome.hk ├── pi.hk ├── pig_latin.hk ├── pythagoras.hk ├── quadratic_roots.hk ├── quick_sort.hk ├── raylib.hk ├── regex.hk ├── rule110.hk ├── selectors.hk ├── shebang.hk ├── sieve_of_eratosthenes.hk ├── tcp_client.hk ├── tcp_server.hk └── tic_tac_toe.hk ├── extensions ├── CMakeLists.txt ├── bigint.c ├── bigint.h ├── crypto.c ├── crypto.h ├── curl.c ├── curl.h ├── deps │ ├── ecc.c │ ├── ecc.h │ ├── geohash.c │ ├── geohash.h │ ├── rc4.c │ ├── rc4.h │ ├── uuid4.c │ └── uuid4.h ├── fastcgi.c ├── fastcgi.h ├── geohash.c ├── geohash.h ├── leveldb.c ├── leveldb.h ├── mysql.c ├── mysql.h ├── raylib_mod.c ├── raylib_mod.h ├── redis.c ├── redis.h ├── regex.c ├── regex.h ├── secp256r1.c ├── secp256r1.h ├── sqlite.c ├── sqlite.h ├── uuid.c ├── uuid.h ├── zeromq.c └── zeromq.h ├── include ├── hook.h └── hook │ ├── array.h │ ├── callable.h │ ├── chunk.h │ ├── compiler.h │ ├── dump.h │ ├── iterable.h │ ├── iterator.h │ ├── memory.h │ ├── range.h │ ├── stack.h │ ├── string.h │ ├── struct.h │ ├── userdata.h │ ├── utils.h │ ├── value.h │ └── vm.h ├── scripts ├── benchmark.sh ├── build-and-install.sh ├── build-with-extensions.bat ├── build.bat ├── build.sh ├── clean.bat ├── clean.sh ├── install.bat ├── install.sh ├── pack-with-extensions.bat ├── pack.bat ├── pack.sh ├── release-with-extensions.bat ├── release.bat ├── test.bat ├── test.sh └── utils.sh ├── src ├── CMakeLists.txt ├── array.c ├── builtin.c ├── builtin.h ├── callable.c ├── chunk.c ├── compiler.c ├── dump.c ├── iterable.c ├── iterator.c ├── lexer.c ├── lexer.h ├── memory.c ├── module.c ├── module.h ├── range.c ├── record.c ├── record.h ├── string.c ├── struct.c ├── userdata.c ├── utils.c ├── value.c └── vm.c └── tests ├── anonymous_function_test.hk ├── arithmetic_assignment_test.hk ├── arithmetic_expression_test.hk ├── array_add_element_test.hk ├── array_compare_test.hk ├── array_concatenation_test.hk ├── array_delete_element_test.hk ├── array_difference_test.hk ├── array_equal_test.hk ├── array_get_element_test.hk ├── array_initializer_test.hk ├── array_resize_test.hk ├── array_set_element_test.hk ├── array_slice_test.hk ├── bitwise_shift_assignment_test.hk ├── bitwise_shift_expression_test.hk ├── branching_statements_and_expressions_test.hk ├── builtin_function_address_test.hk ├── builtin_function_assert_test.hk ├── builtin_function_bin_test.hk ├── builtin_function_cap_test.hk ├── builtin_function_chr_test.hk ├── builtin_function_compare_test.hk ├── builtin_function_exit_test.hk ├── builtin_function_hex_test.hk ├── builtin_function_is_array_test.hk ├── builtin_function_is_bool_test.hk ├── builtin_function_is_callable_test.hk ├── builtin_function_is_comparable_test.hk ├── builtin_function_is_empty_test.hk ├── builtin_function_is_instance_test.hk ├── builtin_function_is_int_test.hk ├── builtin_function_is_iterable_test.hk ├── builtin_function_is_iterator_test.hk ├── builtin_function_is_nil_test.hk ├── builtin_function_is_number_test.hk ├── builtin_function_is_object_test.hk ├── builtin_function_is_range_test.hk ├── builtin_function_is_string_test.hk ├── builtin_function_is_struct_test.hk ├── builtin_function_is_userdata_test.hk ├── builtin_function_join_test.hk ├── builtin_function_len_test.hk ├── builtin_function_ord_test.hk ├── builtin_function_panic_test.hk ├── builtin_function_print_test.hk ├── builtin_function_refcount_test.hk ├── builtin_function_sleep_test.hk ├── builtin_function_split_test.hk ├── builtin_function_to_bool_test.hk ├── builtin_function_to_int_test.hk ├── builtin_function_to_number_test.hk ├── builtin_function_to_string_test.hk ├── builtin_function_type_test.hk ├── error_arrays_index_of_invalid_type_test.hk ├── error_arrays_new_array_invalid_range_capacity_must_be_between_and_test.hk ├── error_arrays_new_array_invalid_type_test.hk ├── error_assert_expected_string_but_got_test.hk ├── error_cannot_call_value_of_type_test.hk ├── error_cannot_create_range_from_non_numbers_test.hk ├── error_compare_cannot_compare_and_test.hk ├── error_exit_expected_number_but_got_test.hk ├── error_expects_argument_but_got_test.hk ├── error_int_cannot_convert_empty_string_to_number_test.hk ├── error_int_cannot_convert_string_to_number_test.hk ├── error_int_cannot_convert_to_integer_test.hk ├── error_int_number_literal_is_too_large_test.hk ├── error_is_empty_has_no_length_test.hk ├── error_len_has_no_length_test.hk ├── error_math_abs_expected_number_but_got_test.hk ├── error_math_ceil_expected_number_but_got_test.hk ├── error_math_floor_expected_number_but_got_test.hk ├── error_math_pow_expected_number_but_got_1_test.hk ├── error_math_pow_expected_number_but_got_2_test.hk ├── error_math_sqrt_expected_number_but_got_test.hk ├── error_num_cannot_convert_empty_string_to_number_test.hk ├── error_num_cannot_convert_string_to_number_test.hk ├── error_num_cannot_convert_to_number_test.hk ├── error_num_number_literal_is_too_large_test.hk ├── error_os_getenv_expected_string_but_got_test.hk ├── error_os_system_expected_string_but_got_test.hk ├── error_panic_expected_string_but_got_test.hk ├── error_stack_overflow_test.hk ├── error_str_cannot_convert_to_string_test.hk ├── error_strings_hash_expected_string_but_got_test.hk ├── error_strings_lower_expected_string_but_got_test.hk ├── error_strings_trim_expected_string_but_got_test.hk ├── error_strings_upper_expected_string_but_got_test.hk ├── error_value_of_type_has_no_capacity_test.hk ├── foreach_test.hk ├── function_call_test.hk ├── function_declaration_test.hk ├── if_statement_var_declaration_test.hk ├── if_with_var_declaration_test.hk ├── import_statement_test.hk ├── iterator_test.hk ├── looping_statements_test.hk ├── main_function_args_test.hk ├── match_statement_expression_test.hk ├── match_statement_var_declaration_test.hk ├── module_arrays_avg_test.hk ├── module_arrays_fill_test.hk ├── module_arrays_index_of_test.hk ├── module_arrays_max_test.hk ├── module_arrays_min_test.hk ├── module_arrays_new_array_test.hk ├── module_arrays_reverse_test.hk ├── module_arrays_sort_test.hk ├── module_arrays_sum_test.hk ├── module_encoding_ascii85_test.hk ├── module_encoding_base32_test.hk ├── module_encoding_base58_test.hk ├── module_encoding_base64_test.hk ├── module_hashing_crc32_test.hk ├── module_hashing_crc64_test.hk ├── module_hashing_md5_test.hk ├── module_hashing_ripemd160_test.hk ├── module_hashing_sha1_test.hk ├── module_hashing_sha224_test.hk ├── module_hashing_sha256_test.hk ├── module_hashing_sha384_test.hk ├── module_hashing_sha3_test.hk ├── module_hashing_sha512_test.hk ├── module_ini_test.hk ├── module_ini_test.ini ├── module_json_decode_test.hk ├── module_json_encode_test.hk ├── module_lists_is_empty_test.hk ├── module_lists_len_test.hk ├── module_lists_pop_back_test.hk ├── module_lists_pop_front_test.hk ├── module_lists_push_back_test.hk ├── module_lists_push_front_test.hk ├── module_math_abs_test.hk ├── module_math_acos_test.hk ├── module_math_asin_test.hk ├── module_math_atan_test.hk ├── module_math_cbrt_test.hk ├── module_math_ceil_test.hk ├── module_math_cos_test.hk ├── module_math_exp_test.hk ├── module_math_floor_test.hk ├── module_math_log10_test.hk ├── module_math_log2_test.hk ├── module_math_log_test.hk ├── module_math_pow_test.hk ├── module_math_round_test.hk ├── module_math_sin_test.hk ├── module_math_sqrt_test.hk ├── module_math_tan_test.hk ├── module_numbers_constants_test.hk ├── module_numbers_srand_rand_test.hk ├── module_os_clock_test.hk ├── module_os_clocks_per_sec_test.hk ├── module_os_getcwd_test.hk ├── module_os_getenv_test.hk ├── module_os_name_test.hk ├── module_os_system_test.hk ├── module_os_time_test.hk ├── module_secp256r1_test.hk ├── module_socket_new_close_test.hk ├── module_strings_ends_with_test.hk ├── module_strings_hash_test.hk ├── module_strings_lower_test.hk ├── module_strings_new_string_test.hk ├── module_strings_repeat_test.hk ├── module_strings_reverse_test.hk ├── module_strings_starts_with_test.hk ├── module_strings_trim_test.hk ├── module_strings_upper_test.hk ├── module_utf8_len_test.hk ├── module_utf8_sub_test.hk ├── nonlocals_test.hk ├── print_scalar_values_test.hk ├── range_test.hk ├── string_concatenation_test.hk ├── string_slice_test.hk ├── struct_declaration_and_initialization_test.hk ├── struct_instance_get_field_test.hk ├── struct_instance_test.hk └── variable_declaration_test.hk /.cpack_ignore: -------------------------------------------------------------------------------- 1 | \\.git/ 2 | \\.github/ 3 | \\.trash/ 4 | \\.vscode/ 5 | 6 | bin/ 7 | build/ 8 | lib/ 9 | package/ 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [fabiosvm] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | #lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | #polar: # Replace with a single Polar username 14 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /.github/workflows/macos-build-extensions.yml: -------------------------------------------------------------------------------- 1 | name: macOS build with extensions 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | macos-build: 11 | runs-on: macos-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Installing dependencies (Homebrew packages) 15 | run: | 16 | brew install sqlite 17 | brew install openssl 18 | brew install fcgi 19 | brew install mysql-client 20 | brew install gmp 21 | brew install zmq 22 | brew install leveldb 23 | brew install pcre 24 | brew install raylib 25 | - name: Installing dependency hiredis 26 | run: | 27 | git clone https://github.com/redis/hiredis.git 28 | cd hiredis 29 | git fetch --all --tags 30 | git checkout tags/v1.0.2 31 | cmake -B build -DCMAKE_BUILD_TYPE=Release 32 | cmake --build build 33 | sudo cmake --install build 34 | - name: Configure CMake 35 | run: | 36 | cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=Debug -DBUILD_EXTENSIONS=1 37 | - name: Build 38 | run: | 39 | cmake --build ${{ github.workspace }}/build 40 | - name: Running tests 41 | run: | 42 | ${{ github.workspace }}/scripts/test.sh 43 | env: 44 | HOOK_HOME: ${{ github.workspace }} 45 | -------------------------------------------------------------------------------- /.github/workflows/macos-build.yml: -------------------------------------------------------------------------------- 1 | name: macOS build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | macos-build: 11 | runs-on: macos-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Configure CMake and build 15 | run: ${{ github.workspace }}/scripts/build.sh 16 | - name: Running tests 17 | run: | 18 | ${{ github.workspace }}/scripts/test.sh 19 | env: 20 | HOOK_HOME: ${{ github.workspace }} 21 | -------------------------------------------------------------------------------- /.github/workflows/macos-release.yml: -------------------------------------------------------------------------------- 1 | name: macOS release 2 | 3 | on: 4 | release: 5 | types: 6 | - created 7 | 8 | jobs: 9 | macos-release: 10 | runs-on: macos-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Configure CMake and build for release 14 | run: ${{ github.workspace }}/scripts/pack.sh 15 | - name: Upload asset 16 | uses: shogo82148/actions-upload-release-asset@v1 17 | with: 18 | upload_url: ${{ github.event.release.upload_url }} 19 | asset_path: ${{ github.workspace }}/package/*.tar.gz 20 | overwrite: true 21 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu-build-extensions.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu build with extensions 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | ubuntu-build-extensions: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Installing dependencies (APT packages) 15 | run: | 16 | sudo apt-get update -y 17 | sudo apt-get install -y libsqlite3-dev 18 | sudo apt-get install -y libcurl4-openssl-dev 19 | sudo apt-get install -y libmysqlclient-dev 20 | sudo apt-get install -y libgmp3-dev 21 | sudo apt-get install -y libzmq3-dev 22 | sudo apt-get install -y libleveldb-dev 23 | sudo apt-get install -y libpcre3-dev 24 | - name: Installing dependency hiredis 25 | run: | 26 | git clone https://github.com/redis/hiredis.git 27 | cd hiredis 28 | git fetch --all --tags 29 | git checkout tags/v1.0.2 30 | cmake -B build -DCMAKE_BUILD_TYPE=Release 31 | cmake --build build 32 | sudo cmake --install build 33 | - name: Installing dependency fcgi2 34 | run: | 35 | git clone https://github.com/FastCGI-Archives/fcgi2.git 36 | cd fcgi2 37 | libtoolize && aclocal && automake --add-missing && autoconf 38 | ./autogen.sh 39 | ./configure 40 | make 41 | sudo make install 42 | - name: Installing dependency raylib 43 | run: | 44 | sudo apt install build-essential 45 | sudo apt install libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev 46 | git clone https://github.com/raysan5/raylib.git 47 | cd raylib 48 | mkdir build && cd build 49 | cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON .. 50 | make 51 | sudo make install 52 | - name: Configure CMake 53 | run: | 54 | cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=Debug -DBUILD_EXTENSIONS=1 55 | - name: Build 56 | run: | 57 | cmake --build ${{ github.workspace }}/build 58 | - name: Running tests 59 | run: | 60 | ${{ github.workspace }}/scripts/test.sh 61 | env: 62 | HOOK_HOME: ${{ github.workspace }} 63 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu-build.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | ubuntu-build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Configure CMake and build 15 | run: ${{ github.workspace }}/scripts/build.sh 16 | - name: Running tests 17 | run: | 18 | ${{ github.workspace }}/scripts/test.sh 19 | env: 20 | HOOK_HOME: ${{ github.workspace }} 21 | - name: Code coverage 22 | run: | 23 | gcov src/*.c 24 | bash <(curl -s https://codecov.io/bash) 25 | env: 26 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu-release.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu release 2 | 3 | on: 4 | release: 5 | types: 6 | - created 7 | 8 | jobs: 9 | ubuntu-release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Configure CMake and build for release 14 | run: ${{ github.workspace }}/scripts/pack.sh 15 | - name: Upload asset 16 | uses: shogo82148/actions-upload-release-asset@v1 17 | with: 18 | upload_url: ${{ github.event.release.upload_url }} 19 | asset_path: ${{ github.workspace }}/package/*.tar.gz 20 | overwrite: true 21 | -------------------------------------------------------------------------------- /.github/workflows/windows-build.yml: -------------------------------------------------------------------------------- 1 | name: Windows build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | windows-build: 11 | runs-on: windows-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Add msbuild to PATH 15 | uses: microsoft/setup-msbuild@v1.1 16 | - name: Configure CMake and build 17 | run: ${{ github.workspace }}/scripts/build.bat 18 | - name: Running tests 19 | run: | 20 | ${{ github.workspace }}/scripts/test.bat 21 | env: 22 | HOOK_HOME: ${{ github.workspace }} 23 | -------------------------------------------------------------------------------- /.github/workflows/windows-release.yml: -------------------------------------------------------------------------------- 1 | name: Windows release 2 | 3 | on: 4 | release: 5 | types: 6 | - created 7 | 8 | jobs: 9 | windows-release: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Add msbuild to PATH 14 | uses: microsoft/setup-msbuild@v1.1 15 | - name: Configure CMake and build for release 16 | run: ${{ github.workspace }}/scripts/pack.bat 17 | - name: Upload asset 18 | uses: shogo82148/actions-upload-release-asset@v1 19 | with: 20 | upload_url: ${{ github.event.release.upload_url }} 21 | asset_path: ${{ github.workspace }}/package/*.tar.gz 22 | overwrite: true 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | bin/ 3 | lib/ 4 | package/ 5 | .vscode/ 6 | .trash/ 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Fábio de Souza Villaça Medeiros 3 | Eduardo de Moura Rodrigues 4 | Augusto 5 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | 2 | # Build Hook from source code 3 | 4 | This project is written in C and uses the CMake build tool. Therefore, you may need to install 5 | this tool on your system. 6 | 7 | Note that the following instructions are for the Ubuntu operating system, but the project is cross-platform, 8 | so you can compile it for Linux, macOS, and Windows. 9 | 10 | ## Installing development tools 11 | 12 | Enter the following commands in the terminal to install CMake: 13 | 14 | ``` 15 | sudo apt-get update -y 16 | sudo apt-get install -y cmake 17 | ``` 18 | 19 | ## Building and compiling 20 | 21 | Use the following commands to build the binaries: 22 | 23 | ``` 24 | cd ~ 25 | git clone https://github.com/hook-lang/hook.git 26 | cd hook 27 | scripts/build.sh 28 | ``` 29 | 30 | ### Building the extensions 31 | 32 | Hook's project brings some extensions (non-core built-in modules) that are not compiled by default. 33 | 34 | To build the extensions, you need to install some dependencies: 35 | 36 | ``` 37 | sudo apt-get install -y libsqlite3-dev libcurl4-openssl-dev libmysqlclient-dev libgmp3-dev libzmq3-dev libleveldb-dev libpcre3-dev 38 | ``` 39 | 40 | So you can build the extensions with the following command: 41 | 42 | ``` 43 | scripts/build.sh Debug with-extensions 44 | ``` 45 | 46 | ### Building for Release 47 | 48 | To build the project for release, you can use the following command: 49 | 50 | ``` 51 | scripts/build.sh Release 52 | ``` 53 | 54 | ## Setting environment variable 55 | 56 | The interpreter needs the environment variable `HOOK_HOME` in order to import modules. 57 | Furthermore, you might want to run scripts from anywhere in the terminal. 58 | 59 | ``` 60 | echo "export HOOK_HOME=$HOME/hook" >> ~/.bashrc 61 | echo "export PATH=\$HOOK_HOME/bin:\$PATH" >> ~/.bashrc 62 | ``` 63 | 64 | ## Running tests 65 | 66 | To run the tests, enter the following: 67 | 68 | ``` 69 | scripts/test.sh 70 | ``` 71 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## 0.1.0 3 | 4 | First version. So everything is new. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Hook Programming Language 2 | 3 | Thank you for your interest in contributing to the Hook Programming Language! This document contains useful information on how to contribute to this project. Please note that by contributing to this project, you agree to the guidelines and rules set forth in this document. 4 | 5 | > **Note**: This document is subject to change without notice. If you have any questions or suggestions, please create an issue in our repository. 6 | 7 | ## How to Contribute 8 | 9 | Any type of contribution is welcome. You can create an issue if you have a `question`, found a `bug`, or want to suggest a new `feature` or `refactoring`. You can also contribute directly by coding a solution and creating a Pull Request. 10 | 11 | Another way to contribute is to browse through the issues and find one that you can help by contributing to its discussion or even coding and making a PR for that issue. 12 | 13 | ### Pull Requests 14 | 15 | To contribute with a PR, follow these steps: 16 | 17 | 1. Fork this repository to your GitHub account. 18 | 2. Create a specific branch for your contribution. 19 | 3. Make your changes and submit a PR. 20 | 4. Wait for the PR to be reviewed by a repository administrator. 21 | 5. Communicate through the PR if necessary. 22 | 6. Make adjustments and send them to your branch copy if necessary. 23 | 24 | Before submitting your PR, make sure that: 25 | 26 | - Your PR contains a clear description of the problem it is solving and how it is solving it. 27 | - Your PR is up-to-date with the main branch of the project. 28 | - Your code is reviewed and tested. 29 | 30 | ### Communication 31 | 32 | If you have any questions, suggestions, or criticisms, please create an issue in our repository. Make sure to describe the problem well, including a step-by-step reproduction of the problem, and if possible, screenshots or logs. 33 | 34 | ### Code Standards 35 | 36 | Currently, this project does not have a formal style guide. However, we recommend that you observe the existing code to capture its style and follow an intuitive standard. 37 | 38 | Some clear patterns are: 39 | 40 | - Use whitespace instead of tabs. And use 2 (two) spaces for each level of indentation. 41 | - Type names ends with `_t`. 42 | - Variable and function names are in `snake_case`. 43 | 44 | We are always open to discussing and adopting new code standards to make the project even more consistent and easy to maintain. If you feel that something needs to be discussed, feel free to create an issue for it. 45 | 46 | ### Commits 47 | 48 | Make atomic and descriptive commits so we can easily track the history of changes. 49 | 50 | ## License 51 | 52 | By contributing to the Hook Programming Language, you agree that your contributions will be licensed under the MIT License. 53 | 54 | Thank you for contributing to our project! 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 The Hook Programming Language Authors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /benchmark/fib.hk: -------------------------------------------------------------------------------- 1 | fn fib(n) => 2 | if (n < 2) n 3 | else fib(n - 1) + fib(n - 2); 4 | 5 | let n = to_int(args[0]); 6 | let m = to_int(args[1]); 7 | for (var i = 0; i < n; i++) 8 | println(fib(m)); 9 | -------------------------------------------------------------------------------- /benchmark/fib.js: -------------------------------------------------------------------------------- 1 | function fib(n) { 2 | if (n < 2) 3 | return n; 4 | return fib(n - 1) + fib(n - 2); 5 | } 6 | 7 | const n = process.argv[2]; 8 | const m = process.argv[3]; 9 | for (let i = 0; i < n; i++) 10 | console.log(fib(m)); 11 | -------------------------------------------------------------------------------- /benchmark/fib.lua: -------------------------------------------------------------------------------- 1 | function fib(n) 2 | if n < 2 then 3 | return n 4 | end 5 | return fib(n - 2) + fib(n - 1) 6 | end 7 | 8 | local n = tonumber(arg[1]) 9 | local m = tonumber(arg[2]) 10 | for i = 1, n do 11 | print(fib(m)) 12 | end 13 | -------------------------------------------------------------------------------- /benchmark/fib.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | HK_LOAD_MODULE_HANDLER(arrays); 17 | 18 | #endif // ARRAYS_H 19 | -------------------------------------------------------------------------------- /core/deps/ascii85.h: -------------------------------------------------------------------------------- 1 | /** @file ascii85.h 2 | * 3 | * @brief Ascii85 encoder and decoder 4 | * 5 | * @par 6 | * @copyright Copyright © 2017 Doug Currie, Londonderry, NH, USA. All rights reserved. 7 | * 8 | * @par 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 10 | * and associated documentation files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 12 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all copies or 16 | * substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | **/ 24 | 25 | #ifndef SLI_ASCII85_H 26 | #define SLI_ASCII85_H 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #include 33 | 34 | enum ascii85_errs_e 35 | { 36 | ascii85_err_out_buf_too_small = -255, 37 | ascii85_err_in_buf_too_large, 38 | ascii85_err_bad_decode_char, 39 | ascii85_err_decode_overflow 40 | }; 41 | 42 | int32_t encode_ascii85 (const uint8_t *inp, int32_t in_length, uint8_t *outp, int32_t out_max_length); 43 | 44 | int32_t decode_ascii85 (const uint8_t *inp, int32_t in_length, uint8_t *outp, int32_t out_max_length); 45 | 46 | int32_t ascii85_get_max_encoded_length (int32_t in_length); 47 | 48 | int32_t ascii85_get_max_decoded_length (int32_t in_length); 49 | 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif /* SLI_ASCII85_H */ 56 | -------------------------------------------------------------------------------- /core/deps/base32.h: -------------------------------------------------------------------------------- 1 | /** 2 | * base32 (de)coder implementation as specified by RFC4648. 3 | * 4 | * Copyright (c) 2010 Adrien Kunysz 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | **/ 24 | 25 | #ifndef __BASE32_H_ 26 | #define __BASE32_H_ 27 | 28 | #include // size_t 29 | 30 | /** 31 | * Returns the length of the output buffer required to encode len bytes of 32 | * data into base32. This is a macro to allow users to define buffer size at 33 | * compilation time. 34 | */ 35 | #define BASE32_LEN(len) (((len)/5)*8 + ((len) % 5 ? 8 : 0)) 36 | 37 | /** 38 | * Returns the length of the output buffer required to decode a base32 string 39 | * of len characters. Please note that len must be a multiple of 8 as per 40 | * definition of a base32 string. This is a macro to allow users to define 41 | * buffer size at compilation time. 42 | */ 43 | #define UNBASE32_LEN(len) (((len)/8)*5) 44 | 45 | /** 46 | * Encode the data pointed to by plain into base32 and store the 47 | * result at the address pointed to by coded. The "coded" argument 48 | * must point to a location that has enough available space 49 | * to store the whole coded string. The resulting string will only 50 | * contain characters from the [A-Z2-7=] set. The "len" arguments 51 | * define how many bytes will be read from the "plain" buffer. 52 | **/ 53 | void base32_encode(const unsigned char *plain, size_t len, unsigned char *coded); 54 | 55 | /** 56 | * Decode the null terminated string pointed to by coded and write 57 | * the decoded data into the location pointed to by plain. The 58 | * "plain" argument must point to a location that has enough available 59 | * space to store the whole decoded string. 60 | * Returns the length of the decoded string. This may be less than 61 | * expected due to padding. If an invalid base32 character is found 62 | * in the coded string, decoding will stop at that point. 63 | **/ 64 | size_t base32_decode(const unsigned char *coded, unsigned char *plain); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /core/deps/base58.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE58_H 2 | #define BASE58_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | extern int base58_encode(const char *in, size_t in_len, char *out, size_t *out_len); 11 | extern int base58_decode(const char *in, size_t in_len, char *out, size_t *out_len); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif /* BASE58_H */ 18 | -------------------------------------------------------------------------------- /core/deps/base64.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_H 2 | #define BASE64_H 3 | 4 | #define BASE64_ENCODE_OUT_SIZE(s) ((unsigned int)((((s) + 2) / 3) * 4 + 1)) 5 | #define BASE64_DECODE_OUT_SIZE(s) ((unsigned int)(((s) / 4) * 3)) 6 | 7 | /* 8 | * out is null-terminated encode string. 9 | * return values is out length, exclusive terminating `\0' 10 | */ 11 | unsigned int 12 | base64_encode(const unsigned char *in, unsigned int inlen, char *out); 13 | 14 | /* 15 | * return values is out length 16 | */ 17 | unsigned int 18 | base64_decode(const char *in, unsigned int inlen, unsigned char *out); 19 | 20 | #endif /* BASE64_H */ 21 | -------------------------------------------------------------------------------- /core/deps/crc32.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRC_CRC32_H 2 | #define _CRC_CRC32_H 3 | 4 | #include 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif /* __cplusplus */ 8 | 9 | uint32_t crc32(const char* s, int len); 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif /* __cplusplus */ 14 | #endif 15 | -------------------------------------------------------------------------------- /core/deps/crc64.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRC_CRC64_H 2 | #define _CRC_CRC64_H 3 | 4 | #include 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif /* __cplusplus */ 8 | 9 | uint64_t crc64(const char *s, int l); 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif /* __cplusplus */ 14 | #endif 15 | -------------------------------------------------------------------------------- /core/deps/ini.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `ini.c` for details. 6 | */ 7 | 8 | #ifndef INI_H 9 | #define INI_H 10 | 11 | #define INI_VERSION "0.1.1" 12 | 13 | typedef struct ini_t ini_t; 14 | 15 | ini_t* ini_load(const char *filename); 16 | void ini_free(ini_t *ini); 17 | const char* ini_get(ini_t *ini, const char *section, const char *key); 18 | int ini_sget(ini_t *ini, const char *section, const char *key, const char *scanfmt, void *dst); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /core/deps/md5.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct{ 7 | uint64_t size; // Size of input in bytes 8 | uint32_t buffer[4]; // Current accumulation of hash 9 | uint8_t input[64]; // Input to be used in the next step 10 | uint8_t digest[16]; // Result of algorithm 11 | }MD5Context; 12 | 13 | void md5Init(MD5Context *ctx); 14 | void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len); 15 | void md5Finalize(MD5Context *ctx); 16 | void md5Step(uint32_t *buffer, uint32_t *input); 17 | 18 | uint8_t* md5String(char *input); 19 | uint8_t* md5File(FILE *file); 20 | -------------------------------------------------------------------------------- /core/deps/ripemd160.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 David Turner 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | void ripemd160(const uint8_t* data, uint32_t data_len, uint8_t* digest_bytes); 28 | -------------------------------------------------------------------------------- /core/deps/sha1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // don't just forward declare as we want to pass it around by value 6 | typedef struct _Sha1Digest 7 | { 8 | uint32_t digest[5]; 9 | } Sha1Digest; 10 | Sha1Digest Sha1Digest_fromStr (const char* src); 11 | void Sha1Digest_toStr (const Sha1Digest* digest, char* dst); 12 | 13 | // Streamable hashing 14 | typedef struct _Sha1Ctx Sha1Ctx; 15 | Sha1Ctx* Sha1Ctx_create (void); 16 | void Sha1Ctx_reset (Sha1Ctx*); 17 | void Sha1Ctx_write (Sha1Ctx*, const void* msg, uint64_t bytes); 18 | Sha1Digest Sha1Ctx_getDigest (Sha1Ctx*); 19 | void Sha1Ctx_release (Sha1Ctx*); 20 | 21 | // Helper for one-off buffer hashing 22 | Sha1Digest Sha1_get (const void* msg, uint64_t bytes); 23 | -------------------------------------------------------------------------------- /core/deps/sha3.h: -------------------------------------------------------------------------------- 1 | // sha3.h 2 | // 19-Nov-11 Markku-Juhani O. Saarinen 3 | 4 | #ifndef SHA3_H 5 | #define SHA3_H 6 | 7 | #include 8 | #include 9 | 10 | #ifndef KECCAKF_ROUNDS 11 | #define KECCAKF_ROUNDS 24 12 | #endif 13 | 14 | #ifndef ROTL64 15 | #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) 16 | #endif 17 | 18 | // state context 19 | typedef struct { 20 | union { // state: 21 | uint8_t b[200]; // 8-bit bytes 22 | uint64_t q[25]; // 64-bit words 23 | } st; 24 | int pt, rsiz, mdlen; // these don't overflow 25 | } sha3_ctx_t; 26 | 27 | // Compression function. 28 | void sha3_keccakf(uint64_t st[25]); 29 | 30 | // OpenSSL - like interfece 31 | int sha3_init(sha3_ctx_t *c, int mdlen); // mdlen = hash output in bytes 32 | int sha3_update(sha3_ctx_t *c, const void *data, size_t len); 33 | int sha3_final(void *md, sha3_ctx_t *c); // digest goes to md 34 | 35 | // compute a sha3 hash (md) of given byte length from "in" 36 | void *sha3(const void *in, size_t inlen, void *md, int mdlen); 37 | 38 | // SHAKE128 and SHAKE256 extensible-output functions 39 | #define shake128_init(c) sha3_init(c, 16) 40 | #define shake256_init(c) sha3_init(c, 32) 41 | #define shake_update sha3_update 42 | 43 | void shake_xof(sha3_ctx_t *c); 44 | void shake_out(sha3_ctx_t *c, void *out, size_t len); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /core/encoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // encoding.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef ENCODING_H 12 | #define ENCODING_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(encoding); 17 | 18 | #endif // ENCODING_H 19 | -------------------------------------------------------------------------------- /core/hashing.h: -------------------------------------------------------------------------------- 1 | // 2 | // hashing.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HASHING_H 12 | #define HASHING_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(hashing); 17 | 18 | #endif // HASHING_H 19 | -------------------------------------------------------------------------------- /core/ini.c: -------------------------------------------------------------------------------- 1 | // 2 | // ini.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "ini.h" 12 | #include "deps/ini.h" 13 | 14 | typedef struct 15 | { 16 | HK_USERDATA_HEADER 17 | ini_t *config; 18 | } IniWrapper; 19 | 20 | static inline IniWrapper *ini_wrapper_new(ini_t *config); 21 | static void ini_wrapper_deinit(HkUserdata *udata); 22 | static void load_call(HkVM *vm, HkValue *args); 23 | static void get_call(HkVM *vm, HkValue *args); 24 | 25 | static inline IniWrapper *ini_wrapper_new(ini_t *config) 26 | { 27 | IniWrapper *wrapper = (IniWrapper *) hk_allocate(sizeof(*wrapper)); 28 | hk_userdata_init((HkUserdata *) wrapper, ini_wrapper_deinit); 29 | wrapper->config = config; 30 | return wrapper; 31 | } 32 | 33 | static void ini_wrapper_deinit(HkUserdata *udata) 34 | { 35 | ini_free(((IniWrapper *) udata)->config); 36 | } 37 | 38 | static void load_call(HkVM *vm, HkValue *args) 39 | { 40 | hk_vm_check_argument_string(vm, args, 1); 41 | hk_return_if_not_ok(vm); 42 | HkString *filename = hk_as_string(args[1]); 43 | ini_t *config = ini_load(filename->chars); 44 | if (!config) 45 | { 46 | hk_vm_push_nil(vm); 47 | return; 48 | } 49 | HkUserdata *udata = (HkUserdata *) ini_wrapper_new(config); 50 | hk_vm_push_userdata(vm, udata); 51 | if (!hk_vm_is_ok(vm)) 52 | ini_wrapper_deinit(udata); 53 | } 54 | 55 | static void get_call(HkVM *vm, HkValue *args) 56 | { 57 | hk_vm_check_argument_userdata(vm, args, 1); 58 | hk_return_if_not_ok(vm); 59 | hk_vm_check_argument_string(vm, args, 2); 60 | hk_return_if_not_ok(vm); 61 | hk_vm_check_argument_string(vm, args, 3); 62 | hk_return_if_not_ok(vm); 63 | IniWrapper *wrapper = (IniWrapper *) hk_as_userdata(args[1]); 64 | HkString *section = hk_as_string(args[2]); 65 | HkString *key = hk_as_string(args[3]); 66 | const char *value = ini_get(wrapper->config, section->chars, key->chars); 67 | if (!value) 68 | { 69 | hk_vm_push_nil(vm); 70 | return; 71 | } 72 | hk_vm_push_string_from_chars(vm, -1, value); 73 | } 74 | 75 | HK_LOAD_MODULE_HANDLER(ini) 76 | { 77 | hk_vm_push_string_from_chars(vm, -1, "ini"); 78 | hk_return_if_not_ok(vm); 79 | hk_vm_push_string_from_chars(vm, -1, "load"); 80 | hk_return_if_not_ok(vm); 81 | hk_vm_push_new_native(vm, "load", 1, load_call); 82 | hk_return_if_not_ok(vm); 83 | hk_vm_push_string_from_chars(vm, -1, "get"); 84 | hk_return_if_not_ok(vm); 85 | hk_vm_push_new_native(vm, "get", 3, get_call); 86 | hk_return_if_not_ok(vm); 87 | hk_vm_construct(vm, 2); 88 | } 89 | -------------------------------------------------------------------------------- /core/ini.h: -------------------------------------------------------------------------------- 1 | // 2 | // ini.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef _INI_H 12 | #define _INI_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(ini); 17 | 18 | #endif // _INI_H 19 | -------------------------------------------------------------------------------- /core/io.h: -------------------------------------------------------------------------------- 1 | // 2 | // io.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef IO_H 12 | #define IO_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(io); 17 | 18 | #endif // IO_H 19 | -------------------------------------------------------------------------------- /core/json.h: -------------------------------------------------------------------------------- 1 | // 2 | // json.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef JSON_H 12 | #define JSON_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(json); 17 | 18 | #endif // JSON_H 19 | -------------------------------------------------------------------------------- /core/lists.h: -------------------------------------------------------------------------------- 1 | // 2 | // lists.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef LISTS_H 12 | #define LISTS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(lists); 17 | 18 | #endif // LISTS_H 19 | -------------------------------------------------------------------------------- /core/math.h: -------------------------------------------------------------------------------- 1 | // 2 | // math.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef MATH_H 12 | #define MATH_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(math); 17 | 18 | #endif // MATH_H 19 | -------------------------------------------------------------------------------- /core/numbers.c: -------------------------------------------------------------------------------- 1 | // 2 | // numbers.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "numbers.h" 12 | #include 13 | #include 14 | 15 | #define PI 3.14159265358979323846264338327950288 16 | #define TAU 6.28318530717958647692528676655900577 17 | 18 | #define LARGEST DBL_MAX 19 | #define SMALLEST DBL_MIN 20 | 21 | #define MAX_INTEGER 9007199254740991.0 22 | #define MIN_INTEGER -9007199254740991.0 23 | 24 | static void srand_call(HkVM *vm, HkValue *args); 25 | static void rand_call(HkVM *vm, HkValue *args); 26 | 27 | static void srand_call(HkVM *vm, HkValue *args) 28 | { 29 | hk_vm_check_argument_number(vm, args, 1); 30 | hk_return_if_not_ok(vm); 31 | srand((uint32_t) hk_as_number(args[1])); 32 | hk_vm_push_nil(vm); 33 | } 34 | 35 | static void rand_call(HkVM *vm, HkValue *args) 36 | { 37 | (void) args; 38 | double result = (double) rand() / RAND_MAX; 39 | hk_vm_push_number(vm, result); 40 | } 41 | 42 | HK_LOAD_MODULE_HANDLER(numbers) 43 | { 44 | hk_vm_push_string_from_chars(vm, -1, "numbers"); 45 | hk_return_if_not_ok(vm); 46 | hk_vm_push_string_from_chars(vm, -1, "PI"); 47 | hk_return_if_not_ok(vm); 48 | hk_vm_push_number(vm, PI); 49 | hk_return_if_not_ok(vm); 50 | hk_vm_push_string_from_chars(vm, -1, "TAU"); 51 | hk_return_if_not_ok(vm); 52 | hk_vm_push_number(vm, TAU); 53 | hk_return_if_not_ok(vm); 54 | hk_vm_push_string_from_chars(vm, -1, "LARGEST"); 55 | hk_return_if_not_ok(vm); 56 | hk_vm_push_number(vm, LARGEST); 57 | hk_return_if_not_ok(vm); 58 | hk_vm_push_string_from_chars(vm, -1, "SMALLEST"); 59 | hk_return_if_not_ok(vm); 60 | hk_vm_push_number(vm, SMALLEST); 61 | hk_return_if_not_ok(vm); 62 | hk_vm_push_string_from_chars(vm, -1, "MAX_INTEGER"); 63 | hk_return_if_not_ok(vm); 64 | hk_vm_push_number(vm, MAX_INTEGER); 65 | hk_return_if_not_ok(vm); 66 | hk_vm_push_string_from_chars(vm, -1, "MIN_INTEGER"); 67 | hk_return_if_not_ok(vm); 68 | hk_vm_push_number(vm, MIN_INTEGER); 69 | hk_return_if_not_ok(vm); 70 | hk_vm_push_string_from_chars(vm, -1, "srand"); 71 | hk_return_if_not_ok(vm); 72 | hk_vm_push_new_native(vm, "srand", 1, srand_call); 73 | hk_return_if_not_ok(vm); 74 | hk_vm_push_string_from_chars(vm, -1, "rand"); 75 | hk_return_if_not_ok(vm); 76 | hk_vm_push_new_native(vm, "rand", 0, rand_call); 77 | hk_return_if_not_ok(vm); 78 | hk_vm_construct(vm, 8); 79 | } 80 | -------------------------------------------------------------------------------- /core/numbers.h: -------------------------------------------------------------------------------- 1 | // 2 | // number.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef NUMBERS_H 12 | #define NUMBERS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(numbers); 17 | 18 | #endif // NUMBERS_H 19 | -------------------------------------------------------------------------------- /core/os.h: -------------------------------------------------------------------------------- 1 | // 2 | // os.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef OS_H 12 | #define OS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(os); 17 | 18 | #endif // OS_H 19 | -------------------------------------------------------------------------------- /core/selectors.h: -------------------------------------------------------------------------------- 1 | // 2 | // selectors.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef SELECTORS_H 12 | #define SELECTORS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(selectors); 17 | 18 | #endif // SELECTORS_H 19 | -------------------------------------------------------------------------------- /core/socket.h: -------------------------------------------------------------------------------- 1 | // 2 | // socket.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef SOCKET_H 12 | #define SOCKET_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(socket); 17 | 18 | #endif // SOCKET_H 19 | -------------------------------------------------------------------------------- /core/strings.h: -------------------------------------------------------------------------------- 1 | // 2 | // strings.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef STRINGS_H 12 | #define STRINGS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(strings); 17 | 18 | #endif // STRINGS_H 19 | -------------------------------------------------------------------------------- /core/utf8.c: -------------------------------------------------------------------------------- 1 | // 2 | // utf8.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "utf8.h" 12 | 13 | static inline int decode_char(unsigned char c); 14 | static void len_call(HkVM *vm, HkValue *args); 15 | static void sub_call(HkVM *vm, HkValue *args); 16 | 17 | static inline int decode_char(unsigned char c) 18 | { 19 | if ((c & 0xc0) == 0x80) 20 | return 0; 21 | if ((c & 0xf8) == 0xf0) 22 | return 4; 23 | if ((c & 0xf0) == 0xe0) 24 | return 3; 25 | if ((c & 0xe0) == 0xc0) 26 | return 2; 27 | return 1; 28 | } 29 | 30 | static void len_call(HkVM *vm, HkValue *args) 31 | { 32 | hk_vm_check_argument_string(vm, args, 1); 33 | hk_return_if_not_ok(vm); 34 | HkString *str = hk_as_string(args[1]); 35 | int result = 0; 36 | for (int i = 0; i < str->length;) 37 | { 38 | int length = decode_char((unsigned char) str->chars[i]); 39 | if (!length) 40 | break; 41 | i += length; 42 | ++result; 43 | } 44 | hk_vm_push_number(vm, result); 45 | } 46 | 47 | static void sub_call(HkVM *vm, HkValue *args) 48 | { 49 | hk_vm_check_argument_string(vm, args, 1); 50 | hk_return_if_not_ok(vm); 51 | hk_vm_check_argument_number(vm, args, 2); 52 | hk_return_if_not_ok(vm); 53 | hk_vm_check_argument_number(vm, args, 3); 54 | hk_return_if_not_ok(vm); 55 | HkString *str = hk_as_string(args[1]); 56 | int start = (int) hk_as_number(args[2]); 57 | int end = (int) hk_as_number(args[3]); 58 | int length = 0; 59 | int i = 0; 60 | while (i < str->length) 61 | { 62 | int n = decode_char((unsigned char) str->chars[i]); 63 | if (!n || length == start) 64 | break; 65 | i += n; 66 | ++length; 67 | } 68 | start = i; 69 | while (i < str->length) 70 | { 71 | int n = decode_char((unsigned char) str->chars[i]); 72 | if (!n || length == end) 73 | break; 74 | i += n; 75 | ++length; 76 | } 77 | end = i; 78 | length = end - start; 79 | char *chars = &str->chars[start]; 80 | hk_vm_push_string_from_chars(vm, length, chars); 81 | } 82 | 83 | HK_LOAD_MODULE_HANDLER(utf8) 84 | { 85 | hk_vm_push_string_from_chars(vm, -1, "utf8"); 86 | hk_return_if_not_ok(vm); 87 | hk_vm_push_string_from_chars(vm, -1, "len"); 88 | hk_return_if_not_ok(vm); 89 | hk_vm_push_new_native(vm, "len", 1, len_call); 90 | hk_return_if_not_ok(vm); 91 | hk_vm_push_string_from_chars(vm, -1, "sub"); 92 | hk_return_if_not_ok(vm); 93 | hk_vm_push_new_native(vm, "sub", 3, sub_call); 94 | hk_return_if_not_ok(vm); 95 | hk_vm_construct(vm, 2); 96 | } 97 | -------------------------------------------------------------------------------- /core/utf8.h: -------------------------------------------------------------------------------- 1 | // 2 | // utf8.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef UTF8_H 12 | #define UTF8_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(utf8); 17 | 18 | #endif // UTF8_H 19 | -------------------------------------------------------------------------------- /docs/built-in.txt: -------------------------------------------------------------------------------- 1 | 2 | print(value) 3 | println(value) 4 | type(value) -> string 5 | is_nil(value) -> bool 6 | is_bool(value) -> bool 7 | is_number(value) -> bool 8 | is_int(value) -> bool 9 | is_string(value) -> bool 10 | is_range(value) -> bool 11 | is_array(value) -> bool 12 | is_struct(value) -> bool 13 | is_instance(value) -> bool 14 | is_iterator(value) -> bool 15 | is_callable(value) -> bool 16 | is_userdata(value) -> bool 17 | is_object(value) -> bool 18 | is_comparable(value) -> bool 19 | is_iterable(value) -> bool 20 | to_bool(value) -> bool 21 | to_int(value: number|string) -> number 22 | to_number(value: number|string) -> number 23 | to_string(value: nil|bool|number|string) -> string 24 | ord(value: string) -> number 25 | chr(value: number) -> string 26 | hex(value: string) -> string 27 | bin(value: string) -> string 28 | address(value) -> string 29 | refcount(value) -> number 30 | cap(value: string|array) -> number 31 | len(value: string|array) -> number 32 | is_empty(value: string|array) -> bool 33 | compare(value1, value2) -> number 34 | split(str: string, separator: string) -> array 35 | join(arr: array, separator: string) -> string 36 | iter(val: iterator|range|array) -> iterator 37 | valid(it: iterator) -> bool 38 | current(it: iterator) -> any 39 | next(it: iterator) -> iterator 40 | sleep(ms: number) 41 | exit(code: number) 42 | assert(assertion, msg: string) 43 | panic(msg: string) 44 | -------------------------------------------------------------------------------- /docs/keywords.txt: -------------------------------------------------------------------------------- 1 | 2 | as 3 | break 4 | continue 5 | del 6 | do 7 | else 8 | false 9 | fn 10 | for 11 | foreach 12 | from 13 | if 14 | if! 15 | import 16 | in 17 | let 18 | loop 19 | match 20 | nil 21 | return 22 | struct 23 | true 24 | var 25 | while 26 | while! 27 | -------------------------------------------------------------------------------- /docs/opcodes.txt: -------------------------------------------------------------------------------- 1 | 2 | OP_NIL 3 | OP_FALSE 4 | OP_TRUE 5 | OP_INT 6 | OP_CONSTANT 7 | OP_RANGE 8 | OP_ARRAY 9 | OP_STRUCT 10 | OP_INSTANCE 11 | OP_CONSTRUCT 12 | OP_ITERATOR 13 | OP_CLOSURE 14 | OP_UNPACK_ARRAY 15 | OP_UNPACK_STRUCT 16 | OP_POP 17 | OP_GLOBAL 18 | OP_NONLOCAL 19 | OP_GET_LOCAL 20 | OP_SET_LOCAL 21 | OP_ADD_ELEMENT 22 | OP_GET_ELEMENT 23 | OP_FETCH_ELEMENT 24 | OP_SET_ELEMENT 25 | OP_PUT_ELEMENT 26 | OP_DELETE_ELEMENT 27 | OP_INPLACE_ADD_ELEMENT 28 | OP_INPLACE_PUT_ELEMENT 29 | OP_INPLACE_DELETE_ELEMENT 30 | OP_GET_FIELD 31 | OP_FETCH_FIELD 32 | OP_SET_FIELD 33 | OP_PUT_FIELD 34 | OP_INPLACE_PUT_FIELD 35 | OP_CURRENT 36 | OP_JUMP 37 | OP_JUMP_IF_FALSE 38 | OP_JUMP_IF_TRUE 39 | OP_JUMP_IF_TRUE_OR_POP 40 | OP_JUMP_IF_FALSE_OR_POP 41 | OP_JUMP_IF_NOT_EQUAL 42 | OP_JUMP_IF_NOT_VALID 43 | OP_NEXT 44 | OP_EQUAL 45 | OP_GREATER 46 | OP_LESS 47 | OP_NOT_EQUAL 48 | OP_NOT_GREATER 49 | OP_NOT_LESS 50 | OP_BITWISE_OR 51 | OP_BITWISE_XOR 52 | OP_BITWISE_AND 53 | OP_LEFT_SHIFT 54 | OP_RIGHT_SHIFT 55 | OP_ADD 56 | OP_SUBTRACT 57 | OP_MULTIPLY 58 | OP_DIVIDE 59 | OP_QUOTIENT 60 | OP_REMAINDER 61 | OP_NEGATE 62 | OP_NOT 63 | OP_BITWISE_NOT 64 | OP_INCREMENT 65 | OP_DECREMENT 66 | OP_CALL 67 | OP_LOAD_MODULE 68 | OP_RETURN 69 | OP_RETURN_NIL 70 | -------------------------------------------------------------------------------- /docs/tokens.txt: -------------------------------------------------------------------------------- 1 | 2 | TOKEN_KIND_EOF EOF 3 | TOKEN_KIND_DOTDOT '..' 4 | TOKEN_KIND_DOT '.' 5 | TOKEN_KIND_COMMA ',' 6 | TOKEN_KIND_COLON ':' 7 | TOKEN_KIND_SEMICOLON ';' 8 | TOKEN_KIND_LPAREN '(' 9 | TOKEN_KIND_RPAREN ')' 10 | TOKEN_KIND_LBRACKET '[' 11 | TOKEN_KIND_RBRACKET ']' 12 | TOKEN_KIND_LBRACE '{' 13 | TOKEN_KIND_RBRACE '}' 14 | TOKEN_KIND_PIPEEQ '|=' 15 | TOKEN_KIND_PIPEPIPE '||' 16 | TOKEN_KIND_PIPE '|' 17 | TOKEN_KIND_CARETEQ '^=' 18 | TOKEN_KIND_CARET '^' 19 | TOKEN_KIND_AMPEQ '&=' 20 | TOKEN_KIND_AMPAMP '&&' 21 | TOKEN_KIND_AMP '&' 22 | TOKEN_KIND_ARROW '=>' 23 | TOKEN_KIND_EQEQ '==' 24 | TOKEN_KIND_EQ '=' 25 | TOKEN_KIND_BANGEQ '!=' 26 | TOKEN_KIND_BANG '!' 27 | TOKEN_KIND_GTEQ '>=' 28 | TOKEN_KIND_GTGTEQ '>>=' 29 | TOKEN_KIND_GTGT '>>' 30 | TOKEN_KIND_GT '>' 31 | TOKEN_KIND_LTEQ '<=' 32 | TOKEN_KIND_LTLTEQ '<<=' 33 | TOKEN_KIND_LTLT '<<' 34 | TOKEN_KIND_LT '<' 35 | TOKEN_KIND_PLUSEQ '+=' 36 | TOKEN_KIND_PLUSPLUS '++' 37 | TOKEN_KIND_PLUS '+' 38 | TOKEN_KIND_DASHEQ '-=' 39 | TOKEN_KIND_DASHDASH '--' 40 | TOKEN_KIND_DASH '-' 41 | TOKEN_KIND_STAREQ '*=' 42 | TOKEN_KIND_STAR '*' 43 | TOKEN_KIND_SLASHEQ '/=' 44 | TOKEN_KIND_SLASH '/' 45 | TOKEN_KIND_TILDESLASHEQ '~/=' 46 | TOKEN_KIND_TILDESLASH '~/' 47 | TOKEN_KIND_TILDE '~' 48 | TOKEN_KIND_PERCENTEQ '%=' 49 | TOKEN_KIND_PERCENT '%' 50 | TOKEN_KIND_INT INT 51 | TOKEN_KIND_FLOAT FLOAT 52 | TOKEN_KIND_STRING STRING 53 | TOKEN_KIND_UNDERSCORE_KW '_' 54 | TOKEN_KIND_AS_KW 'as' 55 | TOKEN_KIND_BREAK_KW 'break' 56 | TOKEN_KIND_CONTINUE_KW 'continue' 57 | TOKEN_KIND_DEL_KW 'del' 58 | TOKEN_KIND_DO_KW 'do' 59 | TOKEN_KIND_ELSE_KW 'else' 60 | TOKEN_KIND_FALSE_KW 'false' 61 | TOKEN_KIND_FN_KW 'fn' 62 | TOKEN_KIND_FOR_KW 'for' 63 | TOKEN_KIND_FOREACH_KW 'foreach' 64 | TOKEN_KIND_FROM_KW 'from' 65 | TOKEN_KIND_IF_KW 'if' 66 | TOKEN_KIND_IFBANG_KW 'if!' 67 | TOKEN_KIND_IMPORT_KW 'import' 68 | TOKEN_KIND_IN_KW 'in' 69 | TOKEN_KIND_LET_KW 'let' 70 | TOKEN_KIND_LOOP_KW 'loop' 71 | TOKEN_KIND_MATCH_KW 'match' 72 | TOKEN_KIND_NIL_KW 'nil' 73 | TOKEN_KIND_RETURN_KW 'return' 74 | TOKEN_KIND_STRUCT_KW 'struct' 75 | TOKEN_KIND_TRUE_KW 'true' 76 | TOKEN_KIND_VAR_KW 'var' 77 | TOKEN_KIND_WHILE_KW 'while' 78 | TOKEN_KIND_WHILEBANG_KW 'while!' 79 | TOKEN_KIND_NAME_KW NAME 80 | -------------------------------------------------------------------------------- /examples/100doors.hk: -------------------------------------------------------------------------------- 1 | // 2 | // 100doors.hk 3 | // 4 | 5 | var square = 1; 6 | var increment = 3; 7 | 8 | println("The open doors are: "); 9 | 10 | for (var door = 1; door <= 100; door++) 11 | { 12 | if (door != square) 13 | continue; 14 | print(to_string(door) + " "); 15 | square += increment; 16 | increment += 2; 17 | } 18 | 19 | println(""); 20 | -------------------------------------------------------------------------------- /examples/99bottles.hk: -------------------------------------------------------------------------------- 1 | // 2 | // 99bottles.hk 3 | // 4 | 5 | var n = 99; 6 | 7 | while (n > 1) { 8 | println(to_string(n) + " bottles of beer on the wall,"); 9 | println(to_string(n) + " bottles of beer!"); 10 | println("You take one down, pass it around,"); 11 | n--; 12 | println(to_string(n) + " bottles of beer on the wall!"); 13 | println(""); 14 | } 15 | 16 | println(to_string(n) + " bottle of beer on the wall,"); 17 | println(to_string(n) + " bottle of beer!"); 18 | println("You take it down, pass it around,"); 19 | println("No more bottles of beer!"); 20 | println(""); 21 | -------------------------------------------------------------------------------- /examples/ackermann.hk: -------------------------------------------------------------------------------- 1 | // 2 | // ackermann.hk 3 | // 4 | 5 | fn ackermann(m, n) { 6 | if (m == 0) 7 | return n + 1; 8 | if (n == 0) 9 | return ackermann(m - 1, 1); 10 | if (n > 0) 11 | return ackermann(m - 1, ackermann(m, n - 1)); 12 | } 13 | 14 | println(ackermann(1, 2)); 15 | -------------------------------------------------------------------------------- /examples/bigint.hk: -------------------------------------------------------------------------------- 1 | // 2 | // bigint.hk 3 | // 4 | 5 | import bigint; 6 | 7 | let a = bigint.new("2222222222222222222222222222222222222222"); 8 | let b = bigint.new(3); 9 | let c = bigint.from_string("f", 16); 10 | let d = bigint.new(7); 11 | 12 | let x = bigint.add(a, b); 13 | let y = bigint.sub(x, c); 14 | let z = bigint.mod(y, d); 15 | 16 | println(bigint.to_string(x)); 17 | println(bigint.to_string(y)); 18 | println(bigint.to_string(z)); 19 | -------------------------------------------------------------------------------- /examples/binary_search.hk: -------------------------------------------------------------------------------- 1 | // 2 | // binary_search.hk 3 | // 4 | 5 | fn binary_search(arr, key) { 6 | var low = 0; 7 | var high = len(arr) - 1; 8 | while (low <= high) { 9 | let middle = to_int((low + high) / 2); 10 | let cmp = compare(key, arr[middle]); 11 | if (cmp > 0) { 12 | low = middle + 1; 13 | continue; 14 | } 15 | if (cmp < 0) { 16 | high = middle - 1; 17 | continue; 18 | } 19 | return middle; 20 | } 21 | return -1; 22 | } 23 | 24 | let arr = [ -1, 0, 3, 5, 9, 12 ]; 25 | println(binary_search(arr, 9)); 26 | -------------------------------------------------------------------------------- /examples/bubble_sort.hk: -------------------------------------------------------------------------------- 1 | // 2 | // bubble_sort.hk 3 | // 4 | 5 | fn sort(arr) { 6 | var n = len(arr); 7 | var has_changed; 8 | do { 9 | has_changed = false; 10 | n--; 11 | for (var i = 0; i < n; i++) { 12 | if (arr[i] > arr[i + 1]) { 13 | let t = arr[i]; 14 | arr[i] = arr[i + 1]; 15 | arr[i + 1] = t; 16 | has_changed = true; 17 | } 18 | } 19 | } while (has_changed); 20 | return arr; 21 | } 22 | 23 | println(sort([5, 2, 7, 3, 0, 1, 4, 6])); 24 | -------------------------------------------------------------------------------- /examples/closure.hk: -------------------------------------------------------------------------------- 1 | // 2 | // closure.hk 3 | // 4 | 5 | let x = 1; 6 | 7 | fn f(y) { 8 | let z = 2; 9 | fn g() { 10 | return x + y + z; 11 | } 12 | return g; 13 | } 14 | 15 | let g = f(3); 16 | let result = g(); 17 | println(result); 18 | -------------------------------------------------------------------------------- /examples/coin_flip.hk: -------------------------------------------------------------------------------- 1 | // 2 | // coin_flip.hk 3 | // 4 | 5 | import { srand, rand } from numbers; 6 | import { time } from os; 7 | import { round } from math; 8 | 9 | srand(time()); 10 | 11 | fn coin_flip(times) { 12 | var heads = 0; 13 | var tails = 0; 14 | for (var i = 0; i < times; i++) { 15 | let n = round(rand() * 1); 16 | if (n == 0) 17 | heads++; 18 | else 19 | tails++; 20 | } 21 | println("heads: " + to_string(heads)); 22 | println("tails: " + to_string(tails)); 23 | } 24 | 25 | coin_flip(10); 26 | -------------------------------------------------------------------------------- /examples/collatz.hk: -------------------------------------------------------------------------------- 1 | // 2 | // collatz.hk 3 | // 4 | 5 | fn collatz(n) { 6 | var count = 0; 7 | while (n != 1) { 8 | count++; 9 | if (n % 2 == 0) 10 | n /= 2; 11 | else 12 | n = n * 3 + 1; 13 | } 14 | return count; 15 | } 16 | 17 | println(collatz(2)); 18 | println(collatz(3)); 19 | println(collatz(4)); 20 | println(collatz(5)); 21 | println(collatz(6)); 22 | -------------------------------------------------------------------------------- /examples/curl.hk: -------------------------------------------------------------------------------- 1 | // 2 | // curl.hk 3 | // 4 | 5 | import curl; 6 | 7 | let c = curl.init("https://api.github.com/repos/hook-lang/hook"); 8 | curl.setopt(c, curl.OPT_HTTPHEADER, ["User-Agent: curl.hk"]); 9 | let response = curl.exec(c); 10 | println(response); 11 | -------------------------------------------------------------------------------- /examples/distance.hk: -------------------------------------------------------------------------------- 1 | // 2 | // distance.hk 3 | // 4 | 5 | import { PI } from numbers; 6 | import { abs, pow, sqrt, sin, asin, cos } from math; 7 | 8 | let EARTH_RADIUS_KM = 6371.009; 9 | 10 | struct Point { 11 | x, y 12 | } 13 | 14 | fn deg_to_rad(deg) => deg * PI / 180.0; 15 | 16 | fn euclidean_distance(p1, p2) { 17 | let dx = abs(p1.x - p2.x); 18 | let dy = abs(p1.y - p2.y); 19 | let x = pow(dx, 2); 20 | let y = pow(dy, 2); 21 | return sqrt(x + y); 22 | } 23 | 24 | fn haversine_distance(p1, p2) { 25 | let lat1 = deg_to_rad(p1.y); 26 | let lng1 = deg_to_rad(p1.x); 27 | let lat2 = deg_to_rad(p2.y); 28 | let lng2 = deg_to_rad(p2.x); 29 | let u = sin((lat2 - lat1) / 2); 30 | let v = sin((lng2 - lng1) / 2); 31 | return 2 * EARTH_RADIUS_KM * asin(sqrt(u * u + cos(lat1) * cos(lat2) * v * v)); 32 | } 33 | 34 | let p1 = Point { 7, 10 }; 35 | let p2 = Point { 11, 13 }; 36 | let result1 = euclidean_distance(p1, p2); 37 | 38 | println("The euclidean distance between p1 and p2 is: " + to_string(result1)); 39 | 40 | let p3 = Point { -43.917214, -19.925845 }; 41 | let p4 = Point { -47.879983, -15.793476 }; 42 | let result2 = haversine_distance(p3, p4); 43 | 44 | println("The haversine distance between p3 and p4 is: " + to_string(result2) + " km"); 45 | -------------------------------------------------------------------------------- /examples/factorial.hk: -------------------------------------------------------------------------------- 1 | // 2 | // factorial.hk 3 | // 4 | 5 | fn factorial(n) { 6 | if (n == 0) 7 | return 1; 8 | return n * factorial(n - 1); 9 | } 10 | 11 | println(factorial(8)); 12 | -------------------------------------------------------------------------------- /examples/fibonacci.hk: -------------------------------------------------------------------------------- 1 | // 2 | // fibonacci.hk 3 | // 4 | 5 | fn fibonacci(n) => 6 | if (n < 2) n 7 | else fibonacci(n - 1) + fibonacci(n - 2); 8 | 9 | println(fibonacci(8)); 10 | -------------------------------------------------------------------------------- /examples/fizzbuzz.hk: -------------------------------------------------------------------------------- 1 | // 2 | // fizzbuzz.hk 3 | // 4 | 5 | foreach (i in 1 .. 10) { 6 | if (i % 3 == 0 && i % 5 == 0) { 7 | println("FizzBuzz"); 8 | continue; 9 | } 10 | if (i % 3 == 0) { 11 | println("Fizz"); 12 | continue; 13 | } 14 | if (i % 5 == 0) { 15 | println("Buzz"); 16 | continue; 17 | } 18 | println(i); 19 | } 20 | -------------------------------------------------------------------------------- /examples/fractal.hk: -------------------------------------------------------------------------------- 1 | // 2 | // fractal.hk 3 | // 4 | 5 | let y_min = -0.2; 6 | let y_max = 0.1; 7 | let x_min = -1.5; 8 | let x_max = -1.1; 9 | let pixels = " .:;+=xX$&"; 10 | 11 | for (var y = 0; y < 40; y++) { 12 | let y0 = (y / 40.0) * (y_max - y_min) + y_min; 13 | for (var x = 0; x < 79; x++) { 14 | let x0 = (x / 78.0) * (x_max - x_min) + x_min; 15 | var x = x0; 16 | var y = y0; 17 | var pixel = ' '; 18 | for (var i = 0; i < 80; i++) { 19 | x = x * x - y * y + x0; 20 | y = 2 * x * y + y0; 21 | if (x * x + y * y > 4) { 22 | pixel = pixels[to_int(i / 8)]; 23 | break; 24 | } 25 | } 26 | print(pixel); 27 | } 28 | println(""); 29 | } 30 | -------------------------------------------------------------------------------- /examples/guessing_game.hk: -------------------------------------------------------------------------------- 1 | // 2 | // guessing_game.hk 3 | // 4 | 5 | import { srand, rand } from numbers; 6 | import { time } from os; 7 | import { stdin, readln } from io; 8 | import { trim } from strings; 9 | 10 | println("Guess the number!"); 11 | 12 | srand(time()); 13 | let secret_number = to_int(1 + rand() * 99); 14 | 15 | loop { 16 | println("Please input your guess."); 17 | 18 | var guess = readln(stdin); 19 | 20 | guess = trim(guess); 21 | 22 | if (is_empty(guess)) 23 | continue; 24 | 25 | guess = to_int(guess); 26 | 27 | println("You guessed: " + to_string(guess)); 28 | 29 | let cmp = compare(guess, secret_number); 30 | 31 | if (cmp < 0) 32 | println("Too small!"); 33 | else if (cmp > 0) 34 | println("Too big!"); 35 | else { 36 | println("You win!"); 37 | break; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/hailstone.hk: -------------------------------------------------------------------------------- 1 | // 2 | // hailstone.hk 3 | // 4 | 5 | fn hailstone(n) { 6 | var seq = [n]; 7 | while (n != 1) { 8 | if (n % 2 == 0) 9 | n /= 2; 10 | else 11 | n = (n * 3) + 1; 12 | seq[] = n; 13 | } 14 | return seq; 15 | } 16 | 17 | println(hailstone(7)); 18 | -------------------------------------------------------------------------------- /examples/hanoi.hk: -------------------------------------------------------------------------------- 1 | // 2 | // hanoi.hk 3 | // 4 | 5 | fn hanoi(n, src, dest, aux) { 6 | if (n == 1) { 7 | println("Move disk 1 from rod " + src + " to rod " + dest + "."); 8 | return; 9 | } 10 | hanoi(n - 1, src, aux, dest); 11 | println("Move disk " + to_string(n) + " from rod " + src + " to rod " + dest + "."); 12 | hanoi(n-1, aux, dest, src); 13 | } 14 | 15 | let n = 4; 16 | hanoi(n, "A", "C", "B"); 17 | -------------------------------------------------------------------------------- /examples/hello.hk: -------------------------------------------------------------------------------- 1 | // 2 | // hello.hk 3 | // 4 | 5 | println("Hello, world!"); 6 | -------------------------------------------------------------------------------- /examples/import.hk: -------------------------------------------------------------------------------- 1 | // 2 | // import.hk 3 | // 4 | 5 | import os; 6 | import { foo, bar } from "module.hk"; 7 | 8 | println(os.clock()); 9 | println(foo()); 10 | println(bar()); 11 | -------------------------------------------------------------------------------- /examples/json.hk: -------------------------------------------------------------------------------- 1 | // 2 | // json.hk 3 | // 4 | 5 | import json; 6 | 7 | struct Person { 8 | name, 9 | age 10 | } 11 | 12 | let p = Person { "John", 42 }; 13 | 14 | let serialized = json.encode(p); 15 | 16 | println(serialized); 17 | 18 | let q = json.decode(serialized); 19 | 20 | println(q.name); 21 | println(q.age); 22 | -------------------------------------------------------------------------------- /examples/knapsack.hk: -------------------------------------------------------------------------------- 1 | // 2 | // knapsack.hk 3 | // 4 | 5 | fn knapsack(weight_cap, weights, values) { 6 | var high = 0; 7 | let n = len(weights); 8 | for (var i = 0; i < n; i++) { 9 | var cap = weights[i]; 10 | var value = values[i]; 11 | let new_cap = weights[i]; 12 | let new_value = values[i]; 13 | for (var j = i + 1; j < n; j++) { 14 | if (cap < weight_cap && cap + weights[j] <= weight_cap) { 15 | cap += weights[j]; 16 | value += values[j]; 17 | } else if (new_cap + weights[j] <= weight_cap) { 18 | cap = new_cap + weights[j]; 19 | value = new_value + values[j]; 20 | } 21 | high = if (value > high) value else high; 22 | } 23 | } 24 | return high; 25 | } 26 | 27 | let weight_cap = 10; 28 | let weights = [3, 6, 3]; 29 | let values = [70, 60, 100]; 30 | println(knapsack(weight_cap, weights, values)); 31 | -------------------------------------------------------------------------------- /examples/knuth_shuffle.hk: -------------------------------------------------------------------------------- 1 | // 2 | // knuth_shuffle.hk 3 | // 4 | 5 | import { srand, rand } from numbers; 6 | import { time } from os; 7 | 8 | srand(time()); 9 | 10 | fn shuffle(arr) { 11 | let n = len(arr); 12 | for (var i = n - 1; i >= 0; i--) { 13 | let j = to_int(rand() * (i - 1)); 14 | let tmp = arr[i]; 15 | arr[i] = arr[j]; 16 | arr[j] = tmp; 17 | } 18 | return arr; 19 | } 20 | 21 | let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 22 | println(shuffle(arr)); 23 | -------------------------------------------------------------------------------- /examples/mandelbrot.hk: -------------------------------------------------------------------------------- 1 | // 2 | // mandelbrot.hk 3 | // 4 | 5 | import { floor } from math; 6 | let pixels = [" ", ".", ":", ";", "+", "=", "x", "X", "$", "&"]; 7 | 8 | let y_min = -0.2; 9 | let y_max = 0.1; 10 | let x_min = -1.5; 11 | let x_max = -1.1; 12 | 13 | for (var y_pixel = 0; y_pixel < 24; y_pixel++) { 14 | let y = (y_pixel / 24) * (y_max - y_min) + y_min; 15 | for (var x_pixel = 0; x_pixel < 80; x_pixel++) { 16 | let x = (x_pixel / 79) * (x_max - x_min) + x_min; 17 | var pixel = " "; 18 | var x0 = x; 19 | var y0 = y; 20 | for (var iter = 0; iter < 80; iter++) { 21 | var x1 = (x0 * x0) - (y0 * y0); 22 | var y1 = 2 * x0 * y0; 23 | x1 = x1 + x; 24 | y1 = y1 + y; 25 | x0 = x1; 26 | y0 = y1; 27 | let d = (x0 * x0) + (y0 * y0); 28 | if (d > 4) { 29 | pixel = pixels[floor(iter / 8)]; 30 | break; 31 | } 32 | } 33 | print(pixel); 34 | } 35 | println(""); 36 | } 37 | -------------------------------------------------------------------------------- /examples/module.hk: -------------------------------------------------------------------------------- 1 | // 2 | // module.hk 3 | // 4 | 5 | struct module { 6 | foo, bar 7 | } 8 | 9 | fn foo() { 10 | return 1; 11 | } 12 | 13 | fn bar() { 14 | return 2; 15 | } 16 | 17 | return module { foo, bar }; 18 | -------------------------------------------------------------------------------- /examples/palindrome.hk: -------------------------------------------------------------------------------- 1 | // 2 | // palindrome.hk 3 | // 4 | 5 | import { reverse } from strings; 6 | 7 | fn palindrome(str) { 8 | return reverse(str) == str; 9 | } 10 | 11 | println(palindrome("mutum")); 12 | -------------------------------------------------------------------------------- /examples/pi.hk: -------------------------------------------------------------------------------- 1 | // 2 | // pi.hk 3 | // 4 | 5 | fn pi() { 6 | let n = 1000000; 7 | var d = 1; 8 | var sum = 0; 9 | for (var i = 0; i < n; i++) { 10 | if (i % 2 == 0) 11 | sum += 4 / d; 12 | else 13 | sum -= 4 / d; 14 | d += 2; 15 | } 16 | return sum; 17 | } 18 | 19 | println(pi()); 20 | -------------------------------------------------------------------------------- /examples/pig_latin.hk: -------------------------------------------------------------------------------- 1 | // 2 | // pig_latin.hk 3 | // 4 | 5 | import { lower } from strings; 6 | 7 | let vowels = ['a', 'e', 'i', 'o', 'u']; 8 | let num_vowels = len(vowels); 9 | 10 | fn pig_latin(word) { 11 | word = lower(word); 12 | let first = word[0]; 13 | 14 | for (var i = 0; i < num_vowels; i++) { 15 | if (first != vowels[i]) 16 | continue; 17 | return word + "way"; 18 | } 19 | word = word[1 .. len(word) - 1]; 20 | word += first + "ay"; 21 | return word; 22 | } 23 | 24 | println(pig_latin("Apple")); 25 | println(pig_latin("Banana")); 26 | println(pig_latin("Cherry")); 27 | println(pig_latin("Damascus")); 28 | println(pig_latin("Eggplant")); 29 | println(pig_latin("Fig")); 30 | -------------------------------------------------------------------------------- /examples/pythagoras.hk: -------------------------------------------------------------------------------- 1 | // 2 | // pythagoras.hk 3 | // 4 | 5 | import { sqrt, pow } from math; 6 | 7 | fn hypothenuse(a, b) { 8 | return sqrt(pow(a, 2) + pow(b, 2)); 9 | } 10 | 11 | println(hypothenuse(3, 4)); 12 | -------------------------------------------------------------------------------- /examples/quadratic_roots.hk: -------------------------------------------------------------------------------- 1 | // 2 | // quadratic_roots.hk 3 | // 4 | 5 | import { sqrt } from math; 6 | 7 | fn quadratic_roots(a, b, c) { 8 | let d = b * b - 4 * a * c; 9 | if (d < 0) 10 | return nil; 11 | let sd = sqrt(d); 12 | let x1 = (-b + sd) / (2 * a); 13 | let x2 = (-b - sd) / (2 * a); 14 | return [x1, x2]; 15 | } 16 | 17 | println(quadratic_roots(1, 3, 2)); 18 | -------------------------------------------------------------------------------- /examples/quick_sort.hk: -------------------------------------------------------------------------------- 1 | // 2 | // quick_sort.hk 3 | // 4 | 5 | fn sort(arr) { 6 | let n = len(arr); 7 | if (n <= 1) 8 | return arr; 9 | let pivot = arr[0]; 10 | var left = []; 11 | var right = []; 12 | for (var i = 1; i < n; i++) { 13 | if (arr[i] < pivot) 14 | left[] = arr[i]; 15 | else 16 | right[] = arr[i]; 17 | } 18 | arr = sort(left); 19 | arr[] = pivot; 20 | arr += sort(right); 21 | return arr; 22 | } 23 | 24 | println(sort([5, 2, 7, 3, 0, 1, 4, 6])); 25 | -------------------------------------------------------------------------------- /examples/raylib.hk: -------------------------------------------------------------------------------- 1 | // 2 | // raylib.hk 3 | // 4 | 5 | import raylib as rl; 6 | 7 | rl.InitWindow(800, 450, "raylib [core] example - basic window"); 8 | 9 | while (!rl.WindowShouldClose()) { 10 | rl.BeginDrawing(); 11 | rl.ClearBackground(rl.RAYWHITE); 12 | rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LIGHTGRAY); 13 | rl.EndDrawing(); 14 | } 15 | 16 | rl.CloseWindow(); 17 | -------------------------------------------------------------------------------- /examples/regex.hk: -------------------------------------------------------------------------------- 1 | // 2 | // regex.hk 3 | // 4 | 5 | import regex; 6 | 7 | let [r, err] = regex.new("a*b"); 8 | if (err) { 9 | panic(err); 10 | } 11 | 12 | println(regex.is_match(r, "aaab")); 13 | println(regex.is_match(r, "ab")); 14 | println(regex.is_match(r, "x")); 15 | -------------------------------------------------------------------------------- /examples/rule110.hk: -------------------------------------------------------------------------------- 1 | // 2 | // rule110.hk 3 | // 4 | 5 | let size = 100; 6 | var prev = []; 7 | var i; 8 | 9 | i = 0; 10 | while (i < size - 1) { 11 | prev[] = false; 12 | i++; 13 | } 14 | prev[] = true; 15 | 16 | fn calc(p, i) { 17 | let prev = p[i - 1]; 18 | let curr = p[i]; 19 | let next = p[i + 1]; 20 | if (prev && curr && next) { 21 | return false; 22 | } 23 | if (prev && curr && !next) { 24 | return true; 25 | } 26 | if (prev && !curr && next) { 27 | return true; 28 | } 29 | if (prev && !curr && !next) { 30 | return false; 31 | } 32 | if (!prev && curr && next) { 33 | return true; 34 | } 35 | if (!prev && curr && !next) { 36 | return true; 37 | } 38 | if (!prev && !curr && next) { 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | i = 0; 45 | while (i < size) { 46 | var line = [false]; 47 | var j; 48 | j = 1; 49 | while (j < size - 1) { 50 | line[] = calc(prev, j); 51 | j++; 52 | } 53 | line[] = false; 54 | var output = ""; 55 | j = 0; 56 | while (j < size) { 57 | output += if (line[j]) "*" else " "; 58 | j++; 59 | } 60 | println(output); 61 | prev = line; 62 | i++; 63 | } 64 | -------------------------------------------------------------------------------- /examples/selectors.hk: -------------------------------------------------------------------------------- 1 | // 2 | // selectors.hk 3 | // 4 | 5 | import selectors; 6 | 7 | println(selectors); 8 | -------------------------------------------------------------------------------- /examples/shebang.hk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env hook 2 | 3 | println("Hello, world!"); 4 | -------------------------------------------------------------------------------- /examples/sieve_of_eratosthenes.hk: -------------------------------------------------------------------------------- 1 | // 2 | // sieve_of_eratosthenes.hk 3 | // 4 | 5 | import { new_array } from arrays; 6 | 7 | fn sieve_of_eratosthenes(n) { 8 | var prime = new_array(n + 1); 9 | var i; 10 | i = 0; 11 | while (i < n + 1) { 12 | prime[] = true; 13 | i++; 14 | } 15 | i = 2; 16 | while (i * i <= n) { 17 | if (prime[i]) { 18 | var j = i * 2; 19 | while (j <= n) { 20 | prime[j] = false; 21 | j += i; 22 | } 23 | } 24 | i++; 25 | } 26 | i = 2; 27 | while (i <= n) { 28 | if (prime[i]) 29 | println(i); 30 | i++; 31 | } 32 | } 33 | 34 | let n = 100; 35 | sieve_of_eratosthenes(n); 36 | -------------------------------------------------------------------------------- /examples/tcp_client.hk: -------------------------------------------------------------------------------- 1 | // 2 | // tcp_client.hk 3 | // 4 | 5 | import socket; 6 | import io; 7 | 8 | let { AF_INET, SOCK_STREAM } = socket; 9 | let { SOL_SOCKET, SO_REUSEADDR } = socket; 10 | let { set_option, connect, writeln, readln, close } = socket; 11 | 12 | let host = "localhost"; 13 | let port = 9000; 14 | 15 | let client = socket.new(AF_INET, SOCK_STREAM, 0); 16 | set_option(client, SOL_SOCKET, SO_REUSEADDR, 1); 17 | connect(client, host, port); 18 | 19 | println("Connected to " + to_string(host) + ":" + to_string(port)); 20 | 21 | loop { 22 | let msg = io.readln(io.stdin); 23 | writeln(client, msg); 24 | let received = readln(client); 25 | if (is_empty(received)) 26 | break; 27 | println(received); 28 | } 29 | 30 | close(client); 31 | println("Server closed connection"); 32 | -------------------------------------------------------------------------------- /examples/tcp_server.hk: -------------------------------------------------------------------------------- 1 | // 2 | // tcp_server.hk 3 | // 4 | 5 | import socket; 6 | 7 | let { AF_INET, SOCK_STREAM } = socket; 8 | let { SOL_SOCKET, SO_REUSEADDR } = socket; 9 | let { set_option, bind, listen, accept, readln, writeln, close } = socket; 10 | 11 | let port = 9000; 12 | 13 | let server = socket.new(AF_INET, SOCK_STREAM, 0); 14 | set_option(server, SOL_SOCKET, SO_REUSEADDR, 1); 15 | bind(server, "0.0.0.0", port); 16 | listen(server, 10); 17 | 18 | let client = accept(server); 19 | if (!client) { 20 | panic("accept failed"); 21 | } 22 | 23 | println("Client connected"); 24 | 25 | loop { 26 | let received = readln(client); 27 | if (is_empty(received)) 28 | break; 29 | println("Received: " + received); 30 | writeln(client, "Reply: " + received); 31 | } 32 | 33 | close(client); 34 | close(server); 35 | println("Client disconnected"); 36 | -------------------------------------------------------------------------------- /examples/tic_tac_toe.hk: -------------------------------------------------------------------------------- 1 | // 2 | // tic_tac_toe.hk 3 | // 4 | 5 | import { stdin, readln } from io; 6 | 7 | fn grid_char(i) { 8 | return match (i) { 9 | -1 => "X", 10 | 0 => " ", 11 | _ => "O" 12 | }; 13 | } 14 | 15 | fn draw(board) { 16 | println(" " + grid_char(board[0]) + " | " + grid_char(board[1]) + " | " + grid_char(board[2])); 17 | println("---+---+---"); 18 | println(" " + grid_char(board[3]) + " | " + grid_char(board[4]) + " | " + grid_char(board[5])); 19 | println("---+---+---"); 20 | println(" " + grid_char(board[6]) + " | " + grid_char(board[7]) + " | " + grid_char(board[8])); 21 | } 22 | 23 | fn win(board) { 24 | let wins = [ 25 | [0, 1, 2], 26 | [3, 4, 5], 27 | [6, 7, 8], 28 | [0, 3, 6], 29 | [1, 4, 7], 30 | [2, 5, 8], 31 | [0, 4, 8], 32 | [2, 4, 6] 33 | ]; 34 | for (var i = 0; i < 8; i++) { 35 | if (board[wins[i][0]] != 0 && board[wins[i][0]] == board[wins[i][1]] && 36 | board[wins[i][0]] == board[wins[i][2]]) 37 | return board[wins[i][2]]; 38 | } 39 | return 0; 40 | } 41 | 42 | fn minimax(board, player) { 43 | var winner = win(board); 44 | if (winner != 0) 45 | return winner * player; 46 | var move = -1; 47 | var score = -2; 48 | for (var i = 0; i < 9; i++) { 49 | if (board[i] == 0) { 50 | board[i] = player; 51 | let this_score = - minimax(board, player * -1); 52 | if (this_score > score) { 53 | score = this_score; 54 | move = i; 55 | } 56 | board[i] = 0; 57 | } 58 | } 59 | if (move == -1) 60 | return 0; 61 | return score; 62 | } 63 | 64 | fn cpu_move(board) { 65 | println("Thinking..."); 66 | var move = -1; 67 | var score = -2; 68 | for (var i = 0; i < 9; i++) { 69 | if (board[i] == 0) { 70 | board[i] = 1; 71 | let temp_score = - minimax(board, -1); 72 | board[i] = 0; 73 | if (temp_score > score) { 74 | score = temp_score; 75 | move = i; 76 | } 77 | } 78 | } 79 | board[move] = 1; 80 | return board; 81 | } 82 | 83 | fn player_move(board) { 84 | var move; 85 | do { 86 | print("Input move ([0..8]): "); 87 | move = to_int(readln(stdin)); 88 | } while (move >= 9 || move < 0 && board[move] == 0); 89 | board[move] = -1; 90 | return board; 91 | } 92 | 93 | var board = [0, 0, 0, 0, 0, 0, 0, 0, 0]; 94 | 95 | println("CPU: O, You: X"); 96 | println("Play (1)st or (2)nd? "); 97 | 98 | let player = to_int(readln(stdin)); 99 | 100 | for (var turn = 0; turn < 9 && win(board) == 0; turn++) { 101 | if ((turn + player) % 2 == 0) { 102 | board = cpu_move(board); 103 | continue; 104 | } 105 | draw(board); 106 | board = player_move(board); 107 | } 108 | 109 | match (win(board)) { 110 | 0 => println("A draw. How droll."); 111 | 1 => { 112 | draw(board); 113 | println("You lose."); 114 | } 115 | -1 => println("You win. Inconceivable!"); 116 | } 117 | -------------------------------------------------------------------------------- /extensions/bigint.h: -------------------------------------------------------------------------------- 1 | // 2 | // bigint.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef BIGINT_H 12 | #define BIGINT_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(bigint); 17 | 18 | #endif // BIGINT_H 19 | -------------------------------------------------------------------------------- /extensions/crypto.h: -------------------------------------------------------------------------------- 1 | // 2 | // crypto.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef CRYPTO_H 12 | #define CRYPTO_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(crypto); 17 | 18 | #endif // CRYPTO_H 19 | -------------------------------------------------------------------------------- /extensions/curl.h: -------------------------------------------------------------------------------- 1 | // 2 | // curl.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef CURL_H 12 | #define CURL_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(curl); 17 | 18 | #endif // CURL_H 19 | -------------------------------------------------------------------------------- /extensions/deps/ecc.h: -------------------------------------------------------------------------------- 1 | #ifndef _EASY_ECC_H_ 2 | #define _EASY_ECC_H_ 3 | 4 | #include 5 | 6 | /* Curve selection options. */ 7 | #define secp128r1 16 8 | #define secp192r1 24 9 | #define secp256r1 32 10 | #define secp384r1 48 11 | #ifndef ECC_CURVE 12 | #define ECC_CURVE secp256r1 13 | #endif 14 | 15 | #if (ECC_CURVE != secp128r1 && ECC_CURVE != secp192r1 && ECC_CURVE != secp256r1 && ECC_CURVE != secp384r1) 16 | #error "Must define ECC_CURVE to one of the available curves" 17 | #endif 18 | 19 | #define ECC_BYTES ECC_CURVE 20 | 21 | #ifdef __cplusplus 22 | extern "C" 23 | { 24 | #endif 25 | 26 | /* ecc_make_key() function. 27 | Create a public/private key pair. 28 | 29 | Outputs: 30 | p_publicKey - Will be filled in with the public key. 31 | p_privateKey - Will be filled in with the private key. 32 | 33 | Returns 1 if the key pair was generated successfully, 0 if an error occurred. 34 | */ 35 | int ecc_make_key(uint8_t p_publicKey[ECC_BYTES+1], uint8_t p_privateKey[ECC_BYTES]); 36 | 37 | /* ecdh_shared_secret() function. 38 | Compute a shared secret given your secret key and someone else's public key. 39 | Note: It is recommended that you hash the result of ecdh_shared_secret before using it for symmetric encryption or HMAC. 40 | 41 | Inputs: 42 | p_publicKey - The public key of the remote party. 43 | p_privateKey - Your private key. 44 | 45 | Outputs: 46 | p_secret - Will be filled in with the shared secret value. 47 | 48 | Returns 1 if the shared secret was generated successfully, 0 if an error occurred. 49 | */ 50 | int ecdh_shared_secret(const uint8_t p_publicKey[ECC_BYTES+1], const uint8_t p_privateKey[ECC_BYTES], uint8_t p_secret[ECC_BYTES]); 51 | 52 | /* ecdsa_sign() function. 53 | Generate an ECDSA signature for a given hash value. 54 | 55 | Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to 56 | this function along with your private key. 57 | 58 | Inputs: 59 | p_privateKey - Your private key. 60 | p_hash - The message hash to sign. 61 | 62 | Outputs: 63 | p_signature - Will be filled in with the signature value. 64 | 65 | Returns 1 if the signature generated successfully, 0 if an error occurred. 66 | */ 67 | int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_hash[ECC_BYTES], uint8_t p_signature[ECC_BYTES*2]); 68 | 69 | /* ecdsa_verify() function. 70 | Verify an ECDSA signature. 71 | 72 | Usage: Compute the hash of the signed data using the same hash as the signer and 73 | pass it to this function along with the signer's public key and the signature values (r and s). 74 | 75 | Inputs: 76 | p_publicKey - The signer's public key 77 | p_hash - The hash of the signed data. 78 | p_signature - The signature value. 79 | 80 | Returns 1 if the signature is valid, 0 if it is invalid. 81 | */ 82 | int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uint8_t p_hash[ECC_BYTES], const uint8_t p_signature[ECC_BYTES*2]); 83 | 84 | #ifdef __cplusplus 85 | } /* end of extern "C" */ 86 | #endif 87 | 88 | #endif /* _EASY_ECC_H_ */ 89 | -------------------------------------------------------------------------------- /extensions/deps/geohash.h: -------------------------------------------------------------------------------- 1 | /* This is a public domain geohash implementation written by WEI Zhicheng. */ 2 | 3 | #ifndef __GEOHASH_H__ 4 | #define __GEOHASH_H__ 5 | 6 | #include 7 | 8 | enum {GEOHASH_OK = 0, GEOHASH_INVALID}; 9 | 10 | int 11 | geohash_encode(double latitude, double longitude, char *hash, size_t len); 12 | 13 | int 14 | geohash_decode(char *hash, double *latitude, double *longitude); 15 | 16 | #endif /* __GEOHASH_H__ */ 17 | -------------------------------------------------------------------------------- /extensions/deps/rc4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * RC4 implementation 3 | * Issue date: 03/18/2006 4 | * 5 | * Copyright (C) 2006 Olivier Gay 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the project nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | #ifndef RC4_H 33 | #define RC4_H 34 | 35 | typedef unsigned char uint8; 36 | typedef unsigned int uint32; 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | typedef struct { 43 | uint8 se[256], sd[256]; 44 | uint32 pose, posd; 45 | uint8 te, td; 46 | } rc4_ctx; 47 | 48 | void rc4_ks(rc4_ctx *ctx, const uint8 *key, uint32 key_len); 49 | void rc4_encrypt(rc4_ctx *ctx, const uint8 *src, uint8 *dst, uint32 len); 50 | void rc4_decrypt(rc4_ctx *ctx, const uint8 *src, uint8 *dst, uint32 len); 51 | 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif /* !RC4_H */ 58 | -------------------------------------------------------------------------------- /extensions/deps/uuid4.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #if defined(_WIN32) 12 | #include 13 | #include 14 | #endif 15 | 16 | #include "uuid4.h" 17 | 18 | 19 | static uint64_t seed[2]; 20 | 21 | 22 | static uint64_t xorshift128plus(uint64_t *s) { 23 | /* http://xorshift.di.unimi.it/xorshift128plus.c */ 24 | uint64_t s1 = s[0]; 25 | const uint64_t s0 = s[1]; 26 | s[0] = s0; 27 | s1 ^= s1 << 23; 28 | s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); 29 | return s[1] + s0; 30 | } 31 | 32 | 33 | int uuid4_init(void) { 34 | #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) 35 | int res; 36 | FILE *fp = fopen("/dev/urandom", "rb"); 37 | if (!fp) { 38 | return UUID4_EFAILURE; 39 | } 40 | res = fread(seed, 1, sizeof(seed), fp); 41 | fclose(fp); 42 | if ( res != sizeof(seed) ) { 43 | return UUID4_EFAILURE; 44 | } 45 | 46 | #elif defined(_WIN32) 47 | int res; 48 | HCRYPTPROV hCryptProv; 49 | res = CryptAcquireContext( 50 | &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); 51 | if (!res) { 52 | return UUID4_EFAILURE; 53 | } 54 | res = CryptGenRandom(hCryptProv, (DWORD) sizeof(seed), (PBYTE) seed); 55 | CryptReleaseContext(hCryptProv, 0); 56 | if (!res) { 57 | return UUID4_EFAILURE; 58 | } 59 | 60 | #else 61 | #error "unsupported platform" 62 | #endif 63 | return UUID4_ESUCCESS; 64 | } 65 | 66 | 67 | void uuid4_generate(char *dst) { 68 | static const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"; 69 | static const char *chars = "0123456789abcdef"; 70 | union { unsigned char b[16]; uint64_t word[2]; } s; 71 | const char *p; 72 | int i, n; 73 | /* get random */ 74 | s.word[0] = xorshift128plus(seed); 75 | s.word[1] = xorshift128plus(seed); 76 | /* build string */ 77 | p = template; 78 | i = 0; 79 | while (*p) { 80 | n = s.b[i >> 1]; 81 | n = (i & 1) ? (n >> 4) : (n & 0xf); 82 | switch (*p) { 83 | case 'x' : *dst = chars[n]; i++; break; 84 | case 'y' : *dst = chars[(n & 0x3) + 8]; i++; break; 85 | default : *dst = *p; 86 | } 87 | dst++, p++; 88 | } 89 | *dst = '\0'; 90 | } 91 | -------------------------------------------------------------------------------- /extensions/deps/uuid4.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef UUID4_H 9 | #define UUID4_H 10 | 11 | #define UUID4_VERSION "1.0.0" 12 | #define UUID4_LEN 37 13 | 14 | enum { 15 | UUID4_ESUCCESS = 0, 16 | UUID4_EFAILURE = -1 17 | }; 18 | 19 | int uuid4_init(void); 20 | void uuid4_generate(char *dst); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /extensions/fastcgi.c: -------------------------------------------------------------------------------- 1 | // 2 | // fastcgi.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "fastcgi.h" 12 | #include 13 | 14 | static void accept_call(HkVM *vm, HkValue *args); 15 | 16 | static void accept_call(HkVM *vm, HkValue *args) 17 | { 18 | (void) args; 19 | hk_vm_push_number(vm, FCGI_Accept()); 20 | } 21 | 22 | HK_LOAD_MODULE_HANDLER(fastcgi) 23 | { 24 | hk_vm_push_string_from_chars(vm, -1, "fastcgi"); 25 | hk_return_if_not_ok(vm); 26 | hk_vm_push_string_from_chars(vm, -1, "accept"); 27 | hk_return_if_not_ok(vm); 28 | hk_vm_push_new_native(vm, "accept", 0, accept_call); 29 | hk_return_if_not_ok(vm); 30 | hk_vm_construct(vm, 1); 31 | } 32 | -------------------------------------------------------------------------------- /extensions/fastcgi.h: -------------------------------------------------------------------------------- 1 | // 2 | // fastcgi.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef FASTCGI_H 12 | #define FASTCGI_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(fastcgi); 17 | 18 | #endif // FASTCGI_H 19 | -------------------------------------------------------------------------------- /extensions/geohash.c: -------------------------------------------------------------------------------- 1 | // 2 | // geohash.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "geohash.h" 12 | #include "deps/geohash.h" 13 | 14 | static void encode_call(HkVM *vm, HkValue *args); 15 | static void decode_call(HkVM *vm, HkValue *args); 16 | 17 | static void encode_call(HkVM *vm, HkValue *args) 18 | { 19 | hk_vm_check_argument_number(vm, args, 1); 20 | hk_return_if_not_ok(vm); 21 | hk_vm_check_argument_number(vm, args, 2); 22 | hk_return_if_not_ok(vm); 23 | double lat = hk_as_number(args[1]); 24 | double lon = hk_as_number(args[2]); 25 | char buf[16] = {0}; 26 | if (geohash_encode(lat, lon, buf, sizeof(buf)) != GEOHASH_OK) 27 | { 28 | hk_vm_push_nil(vm); 29 | return; 30 | } 31 | HkString *str = hk_string_from_chars(-1, buf); 32 | hk_vm_push_string(vm, str); 33 | if (!hk_vm_is_ok(vm)) 34 | hk_string_free(str); 35 | } 36 | 37 | static void decode_call(HkVM *vm, HkValue *args) 38 | { 39 | hk_vm_check_argument_string(vm, args, 1); 40 | hk_return_if_not_ok(vm); 41 | HkString *str = hk_as_string(args[1]); 42 | double lat = 0.0; 43 | double lon = 0.0; 44 | if (geohash_decode(str->chars, &lat, &lon) != GEOHASH_OK) 45 | { 46 | hk_vm_push_nil(vm); 47 | return; 48 | } 49 | HkArray *arr = hk_array_new_with_capacity(2); 50 | hk_array_inplace_append_element(arr, hk_number_value(lat)); 51 | hk_array_inplace_append_element(arr, hk_number_value(lon)); 52 | hk_vm_push_array(vm, arr); 53 | if (!hk_vm_is_ok(vm)) 54 | hk_array_free(arr); 55 | } 56 | 57 | HK_LOAD_MODULE_HANDLER(geohash) 58 | { 59 | hk_vm_push_string_from_chars(vm, -1, "geohash"); 60 | hk_return_if_not_ok(vm); 61 | hk_vm_push_string_from_chars(vm, -1, "encode"); 62 | hk_return_if_not_ok(vm); 63 | hk_vm_push_new_native(vm, "encode", 2, encode_call); 64 | hk_return_if_not_ok(vm); 65 | hk_vm_push_string_from_chars(vm, -1, "decode"); 66 | hk_return_if_not_ok(vm); 67 | hk_vm_push_new_native(vm, "decode", 1, decode_call); 68 | hk_return_if_not_ok(vm); 69 | hk_vm_construct(vm, 2); 70 | } 71 | -------------------------------------------------------------------------------- /extensions/geohash.h: -------------------------------------------------------------------------------- 1 | // 2 | // geohash.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef GEOHASH_H 12 | #define GEOHASH_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(geohash); 17 | 18 | #endif // GEOHASH_H 19 | -------------------------------------------------------------------------------- /extensions/leveldb.h: -------------------------------------------------------------------------------- 1 | // 2 | // leveldb.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef LEVELDB_H 12 | #define LEVELDB_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(leveldb); 17 | 18 | #endif // LEVELDB_H 19 | -------------------------------------------------------------------------------- /extensions/mysql.h: -------------------------------------------------------------------------------- 1 | // 2 | // mysql.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef MYSQL_H 12 | #define MYSQL_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(mysql); 17 | 18 | #endif // MYSQL_H 19 | -------------------------------------------------------------------------------- /extensions/raylib_mod.h: -------------------------------------------------------------------------------- 1 | // 2 | // raylib_mod.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef RAYLIB_MOD_H 12 | #define RAYLIB_MOD_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(raylib); 17 | 18 | #endif // RAYLIB_MOD_H 19 | -------------------------------------------------------------------------------- /extensions/redis.h: -------------------------------------------------------------------------------- 1 | // 2 | // redis.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef REDIS_H 12 | #define REDIS_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(redis); 17 | 18 | #endif // REDIS_H 19 | -------------------------------------------------------------------------------- /extensions/regex.c: -------------------------------------------------------------------------------- 1 | // 2 | // regex.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "regex.h" 12 | #include 13 | 14 | typedef struct 15 | { 16 | HK_USERDATA_HEADER 17 | pcre *pcre; 18 | } Regex; 19 | 20 | static inline Regex *regex_new(pcre *pcre); 21 | static void regex_deinit(HkUserdata *udata); 22 | static void new_call(HkVM *vm, HkValue *args); 23 | static void is_match_call(HkVM *vm, HkValue *args); 24 | 25 | static inline Regex *regex_new(pcre *pcre) 26 | { 27 | Regex *regex = (Regex *) hk_allocate(sizeof(*regex)); 28 | hk_userdata_init((HkUserdata *) regex, regex_deinit); 29 | regex->pcre = pcre; 30 | return regex; 31 | } 32 | 33 | static void regex_deinit(HkUserdata *udata) 34 | { 35 | pcre_free(((Regex *) udata)->pcre); 36 | } 37 | 38 | static void new_call(HkVM *vm, HkValue *args) 39 | { 40 | hk_vm_check_argument_string(vm, args, 1); 41 | hk_return_if_not_ok(vm); 42 | HkString *pattern = hk_as_string(args[1]); 43 | const char *error; 44 | int offset; 45 | pcre *pcre = pcre_compile(pattern->chars, 0, &error, &offset, NULL); 46 | HkArray *arr = hk_array_new_with_capacity(2); 47 | if (!pcre) 48 | { 49 | char message[128]; 50 | snprintf(message, sizeof(message), "compilation failed at offset %d: %s", offset, error); 51 | hk_array_inplace_append_element(arr, hk_nil_value()); 52 | hk_array_inplace_append_element(arr, hk_string_value(hk_string_from_chars(-1, message))); 53 | hk_vm_push_array(vm, arr); 54 | return; 55 | } 56 | HkUserdata *udata = (HkUserdata *) regex_new(pcre); 57 | hk_array_inplace_append_element(arr, hk_userdata_value(udata)); 58 | hk_array_inplace_append_element(arr, hk_nil_value()); 59 | hk_vm_push_array(vm, arr); 60 | if (!hk_vm_is_ok(vm)) 61 | regex_deinit(udata); 62 | } 63 | 64 | static void is_match_call(HkVM *vm, HkValue *args) 65 | { 66 | hk_vm_check_argument_userdata(vm, args, 1); 67 | hk_return_if_not_ok(vm); 68 | hk_vm_check_argument_string(vm, args, 2); 69 | hk_return_if_not_ok(vm); 70 | pcre *pcre = ((Regex *) hk_as_userdata(args[1]))->pcre; 71 | HkString *subject = hk_as_string(args[2]); 72 | int rc = pcre_exec(pcre, NULL, subject->chars, subject->length, 0, 0, NULL, 0); 73 | hk_vm_push_bool(vm, rc >= 0); 74 | } 75 | 76 | HK_LOAD_MODULE_HANDLER(regex) 77 | { 78 | hk_vm_push_string_from_chars(vm, -1, "regex"); 79 | hk_return_if_not_ok(vm); 80 | hk_vm_push_string_from_chars(vm, -1, "new"); 81 | hk_return_if_not_ok(vm); 82 | hk_vm_push_new_native(vm, "new", 1, new_call); 83 | hk_return_if_not_ok(vm); 84 | hk_vm_push_string_from_chars(vm, -1, "is_match"); 85 | hk_return_if_not_ok(vm); 86 | hk_vm_push_new_native(vm, "is_match", 2, is_match_call); 87 | hk_return_if_not_ok(vm); 88 | hk_vm_construct(vm, 2); 89 | } 90 | -------------------------------------------------------------------------------- /extensions/regex.h: -------------------------------------------------------------------------------- 1 | // 2 | // regex.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef REGEX_H 12 | #define REGEX_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(regex); 17 | 18 | #endif // REGEX_H 19 | -------------------------------------------------------------------------------- /extensions/secp256r1.h: -------------------------------------------------------------------------------- 1 | // 2 | // secp256r1.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef SECP256R1_H 12 | #define SECP256R1_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(secp256r1); 17 | 18 | #endif // SECP256R1_H 19 | -------------------------------------------------------------------------------- /extensions/sqlite.h: -------------------------------------------------------------------------------- 1 | // 2 | // sqlite.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef SQLITE_H 12 | #define SQLITE_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(sqlite); 17 | 18 | #endif // SQLITE_H 19 | -------------------------------------------------------------------------------- /extensions/uuid.c: -------------------------------------------------------------------------------- 1 | // 2 | // uuid.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "uuid.h" 12 | #include "deps/uuid4.h" 13 | 14 | static void random_call(HkVM *vm, HkValue *args); 15 | 16 | static void random_call(HkVM *vm, HkValue *args) 17 | { 18 | (void) args; 19 | HkString *str = hk_string_new_with_capacity(UUID4_LEN); 20 | uuid4_init(); 21 | uuid4_generate(str->chars); 22 | str->length = UUID4_LEN; 23 | str->chars[str->length] = '\0'; 24 | hk_vm_push_string(vm, str); 25 | } 26 | 27 | HK_LOAD_MODULE_HANDLER(uuid) 28 | { 29 | hk_vm_push_string_from_chars(vm, -1, "uuid"); 30 | hk_return_if_not_ok(vm); 31 | hk_vm_push_string_from_chars(vm, -1, "random"); 32 | hk_return_if_not_ok(vm); 33 | hk_vm_push_new_native(vm, "random", 0, random_call); 34 | hk_return_if_not_ok(vm); 35 | hk_vm_construct(vm, 1); 36 | } 37 | -------------------------------------------------------------------------------- /extensions/uuid.h: -------------------------------------------------------------------------------- 1 | // 2 | // uuid.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef UUID_H 12 | #define UUID_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(uuid); 17 | 18 | #endif // UUID_H 19 | -------------------------------------------------------------------------------- /extensions/zeromq.h: -------------------------------------------------------------------------------- 1 | // 2 | // zeromq.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef ZEROMQ_H 12 | #define ZEROMQ_H 13 | 14 | #include 15 | 16 | HK_LOAD_MODULE_HANDLER(zeromq); 17 | 18 | #endif // ZEROMQ_H 19 | -------------------------------------------------------------------------------- /include/hook.h: -------------------------------------------------------------------------------- 1 | // 2 | // hook.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HOOK_H 12 | #define HOOK_H 13 | 14 | #include "hook/array.h" 15 | #include "hook/callable.h" 16 | #include "hook/chunk.h" 17 | #include "hook/compiler.h" 18 | #include "hook/dump.h" 19 | #include "hook/iterable.h" 20 | #include "hook/iterator.h" 21 | #include "hook/memory.h" 22 | #include "hook/range.h" 23 | #include "hook/stack.h" 24 | #include "hook/string.h" 25 | #include "hook/struct.h" 26 | #include "hook/userdata.h" 27 | #include "hook/utils.h" 28 | #include "hook/value.h" 29 | #include "hook/vm.h" 30 | 31 | #endif // HOOK_H 32 | -------------------------------------------------------------------------------- /include/hook/array.h: -------------------------------------------------------------------------------- 1 | // 2 | // array.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_ARRAY_H 12 | #define HK_ARRAY_H 13 | 14 | #include "iterator.h" 15 | #include "value.h" 16 | 17 | #define HK_ARRAY_MIN_CAPACITY (1 << 3) 18 | 19 | #define hk_array_is_empty(a) (!(a)->length) 20 | #define hk_array_get_element(a, i) ((a)->elements[(i)]) 21 | 22 | typedef struct 23 | { 24 | HK_OBJECT_HEADER 25 | int capacity; 26 | int length; 27 | HkValue *elements; 28 | } HkArray; 29 | 30 | HkArray *hk_array_new(void); 31 | HkArray *hk_array_new_with_capacity(int minCapacity); 32 | void hk_array_ensure_capacity(HkArray *arr, int minCapacity); 33 | void hk_array_free(HkArray *arr); 34 | void hk_array_release(HkArray *arr); 35 | int hk_array_index_of(HkArray *arr, HkValue elem); 36 | HkArray *hk_array_append_element(HkArray *arr, HkValue elem); 37 | HkArray *hk_array_set_element(HkArray *arr, int index, HkValue elem); 38 | HkArray *hk_array_insert_element(HkArray *arr, int index, HkValue elem); 39 | HkArray *hk_array_delete_element(HkArray *arr, int index); 40 | HkArray *hk_array_concat(HkArray *arr1, HkArray *arr2); 41 | HkArray *hk_array_diff(HkArray *arr1, HkArray *arr2); 42 | void hk_array_inplace_append_element(HkArray *arr, HkValue elem); 43 | void hk_array_inplace_set_element(HkArray *arr, int index, HkValue elem); 44 | void hk_array_inplace_insert_element(HkArray *arr, int index, HkValue elem); 45 | void hk_array_inplace_delete_element(HkArray *arr, int index); 46 | void hk_array_inplace_concat(HkArray *dest, HkArray *src); 47 | void hk_array_inplace_diff(HkArray *dest, HkArray *src); 48 | void hk_array_inplace_clear(HkArray *arr); 49 | void hk_array_print(HkArray *arr); 50 | bool hk_array_equal(HkArray *arr1, HkArray *arr2); 51 | bool hk_array_compare(HkArray *arr1, HkArray *arr2, int *result); 52 | HkIterator *hk_array_new_iterator(HkArray *arr); 53 | HkArray *hk_array_reverse(HkArray *arr); 54 | bool hk_array_sort(HkArray *arr, HkArray **result); 55 | void hk_array_serialize(HkArray *arr, FILE *stream); 56 | HkArray *hk_array_deserialize(FILE *stream); 57 | 58 | #endif // HK_ARRAY_H 59 | -------------------------------------------------------------------------------- /include/hook/callable.h: -------------------------------------------------------------------------------- 1 | // 2 | // callable.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_CALLABLE_H 12 | #define HK_CALLABLE_H 13 | 14 | #include "chunk.h" 15 | #include "string.h" 16 | 17 | typedef struct HkFunction 18 | { 19 | HK_OBJECT_HEADER 20 | int arity; 21 | HkString *name; 22 | HkString *file; 23 | HkChunk chunk; 24 | uint8_t functionsCapacity; 25 | uint8_t functionsLength; 26 | struct HkFunction **functions; 27 | uint8_t numNonlocals; 28 | } HkFunction; 29 | 30 | typedef struct 31 | { 32 | HK_OBJECT_HEADER 33 | HkFunction *fn; 34 | HkValue nonlocals[1]; 35 | } HkClosure; 36 | 37 | struct HkVM; 38 | 39 | typedef void (*HkCallFn)(struct HkVM *, HkValue *); 40 | 41 | typedef struct 42 | { 43 | HK_OBJECT_HEADER 44 | int arity; 45 | HkString *name; 46 | HkCallFn call; 47 | } HkNative; 48 | 49 | HkFunction *hk_function_new(int arity, HkString *name, HkString *file); 50 | void hk_function_free(HkFunction *fn); 51 | void hk_function_release(HkFunction *fn); 52 | void hk_function_append_child(HkFunction *fn, HkFunction *child); 53 | void hk_function_serialize(HkFunction *fn, FILE *stream); 54 | HkFunction *hk_function_deserialize(FILE *stream); 55 | HkClosure *hk_closure_new(HkFunction *fn); 56 | void hk_closure_free(HkClosure *cl); 57 | void hk_closure_release(HkClosure *cl); 58 | HkNative *hk_native_new(HkString *name, int arity, HkCallFn call); 59 | void hk_native_free(HkNative *native); 60 | void hk_native_release(HkNative *native); 61 | 62 | #endif // HK_CALLABLE_H 63 | -------------------------------------------------------------------------------- /include/hook/chunk.h: -------------------------------------------------------------------------------- 1 | // 2 | // chunk.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_CHUNK_H 12 | #define HK_CHUNK_H 13 | 14 | #include "array.h" 15 | 16 | typedef enum 17 | { 18 | HK_OP_NIL, HK_OP_FALSE, HK_OP_TRUE, 19 | HK_OP_INT, HK_OP_CONSTANT, HK_OP_RANGE, 20 | HK_OP_ARRAY, HK_OP_STRUCT, HK_OP_INSTANCE, 21 | HK_OP_CONSTRUCT, HK_OP_ITERATOR, HK_OP_CLOSURE, 22 | HK_OP_UNPACK_ARRAY, HK_OP_UNPACK_STRUCT, HK_OP_POP, 23 | HK_OP_GLOBAL, HK_OP_NONLOCAL, HK_OP_GET_LOCAL, 24 | HK_OP_SET_LOCAL, HK_OP_APPEND_ELEMENT, HK_OP_GET_ELEMENT, 25 | HK_OP_FETCH_ELEMENT, HK_OP_SET_ELEMENT, HK_OP_PUT_ELEMENT, 26 | HK_OP_DELETE_ELEMENT, HK_OP_INPLACE_APPEND_ELEMENT, HK_OP_INPLACE_PUT_ELEMENT, 27 | HK_OP_INPLACE_DELETE_ELEMENT, HK_OP_GET_FIELD, HK_OP_FETCH_FIELD, 28 | HK_OP_SET_FIELD, HK_OP_PUT_FIELD, HK_OP_INPLACE_PUT_FIELD, 29 | HK_OP_CURRENT, HK_OP_JUMP, HK_OP_JUMP_IF_FALSE, 30 | HK_OP_JUMP_IF_TRUE, HK_OP_JUMP_IF_TRUE_OR_POP, HK_OP_JUMP_IF_FALSE_OR_POP, 31 | HK_OP_JUMP_IF_NOT_EQUAL, HK_OP_JUMP_IF_NOT_VALID, HK_OP_NEXT, 32 | HK_OP_EQUAL, HK_OP_GREATER, HK_OP_LESS, 33 | HK_OP_NOT_EQUAL, HK_OP_NOT_GREATER, HK_OP_NOT_LESS, 34 | HK_OP_BITWISE_OR, HK_OP_BITWISE_XOR, HK_OP_BITWISE_AND, 35 | HK_OP_LEFT_SHIFT, HK_OP_RIGHT_SHIFT, HK_OP_ADD, 36 | HK_OP_SUBTRACT, HK_OP_MULTIPLY, HK_OP_DIVIDE, 37 | HK_OP_QUOTIENT, HK_OP_REMAINDER, HK_OP_NEGATE, 38 | HK_OP_NOT, HK_OP_BITWISE_NOT, HK_OP_INCREMENT, 39 | HK_OP_DECREMENT, HK_OP_CALL, HK_OP_LOAD_MODULE, 40 | HK_OP_RETURN, HK_OP_RETURN_NIL 41 | } HkOpCode; 42 | 43 | typedef struct 44 | { 45 | int no; 46 | int offset; 47 | } HkLine; 48 | 49 | typedef struct 50 | { 51 | int codeCapacity; 52 | int codeLength; 53 | uint8_t *code; 54 | int linesCapacity; 55 | int linesLength; 56 | HkLine *lines; 57 | HkArray *consts; 58 | } HkChunk; 59 | 60 | void hk_chunk_init(HkChunk *chunk); 61 | void hk_chunk_deinit(HkChunk *chunk); 62 | void hk_chunk_emit_byte(HkChunk *chunk, uint8_t byte); 63 | void hk_chunk_emit_word(HkChunk *chunk, uint16_t word); 64 | void hk_chunk_emit_opcode(HkChunk *chunk, HkOpCode op); 65 | void hk_chunk_append_line(HkChunk *chunk, int no); 66 | int hk_chunk_get_line(HkChunk *chunk, int offset); 67 | void hk_chunk_serialize(HkChunk *chunk, FILE *stream); 68 | bool hk_chunk_deserialize(HkChunk *chunk, FILE *stream); 69 | 70 | #endif // HK_CHUNK_H 71 | -------------------------------------------------------------------------------- /include/hook/compiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // compiler.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_COMPILER_H 12 | #define HK_COMPILER_H 13 | 14 | #include "callable.h" 15 | 16 | #define HK_COMPILER_FLAG_NONE 0x00 17 | #define HK_COMPILER_FLAG_ANALYZE 0x01 18 | 19 | HkClosure *hk_compile(HkString *file, HkString *source, int flags); 20 | 21 | #endif // HK_COMPILER_H 22 | -------------------------------------------------------------------------------- /include/hook/dump.h: -------------------------------------------------------------------------------- 1 | // 2 | // dump.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_DUMP_H 12 | #define HK_DUMP_H 13 | 14 | #include "callable.h" 15 | 16 | void hk_dump(HkFunction *fn, FILE *stream); 17 | 18 | #endif // HK_DUMP_H 19 | -------------------------------------------------------------------------------- /include/hook/iterable.h: -------------------------------------------------------------------------------- 1 | // 2 | // iterable.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_ITERABLE_H 12 | #define HK_ITERABLE_H 13 | 14 | #include "iterator.h" 15 | 16 | HkIterator *hk_new_iterator(HkValue val); 17 | 18 | #endif // HK_ITERABLE_H 19 | -------------------------------------------------------------------------------- /include/hook/iterator.h: -------------------------------------------------------------------------------- 1 | // 2 | // iterator.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_ITERATOR_H 12 | #define HK_ITERATOR_H 13 | 14 | #include "value.h" 15 | 16 | #define HK_ITERATOR_HEADER HK_OBJECT_HEADER \ 17 | void (*deinit)(struct HkIterator *); \ 18 | bool (*isValid)(struct HkIterator *); \ 19 | HkValue (*getCurrent)(struct HkIterator *); \ 20 | struct HkIterator *(*next)(struct HkIterator *); \ 21 | void (*inplaceNext)(struct HkIterator *); 22 | 23 | typedef struct HkIterator 24 | { 25 | HK_ITERATOR_HEADER 26 | } HkIterator; 27 | 28 | void hk_iterator_init(HkIterator *it, void (*deinit)(HkIterator *), 29 | bool (*isValid)(HkIterator *), HkValue (*getCurrent)(HkIterator *), 30 | HkIterator *(*next)(HkIterator *), void (*inplaceNext)(HkIterator *)); 31 | void hk_iterator_free(HkIterator *it); 32 | void hk_iterator_release(HkIterator *it); 33 | bool hk_iterator_is_valid(HkIterator *it); 34 | HkValue hk_iterator_get_current(HkIterator *it); 35 | HkIterator *hk_iterator_next(HkIterator *it); 36 | void hk_iterator_inplace_next(HkIterator *it); 37 | 38 | #endif // HK_ITERATOR_H 39 | -------------------------------------------------------------------------------- /include/hook/memory.h: -------------------------------------------------------------------------------- 1 | // 2 | // memory.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_MEMORY_H 12 | #define HK_MEMORY_H 13 | 14 | #include 15 | 16 | void *hk_allocate(size_t size); 17 | void *hk_reallocate(void *ptr, size_t size); 18 | void hk_free(void *ptr); 19 | 20 | #endif // HK_MEMORY_H 21 | -------------------------------------------------------------------------------- /include/hook/range.h: -------------------------------------------------------------------------------- 1 | // 2 | // range.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_RANGE_H 12 | #define HK_RANGE_H 13 | 14 | #include "iterator.h" 15 | #include "value.h" 16 | 17 | typedef struct 18 | { 19 | HK_OBJECT_HEADER 20 | int step; 21 | int64_t start; 22 | int64_t end; 23 | } HkRange; 24 | 25 | HkRange *hk_range_new(int64_t start, int64_t end); 26 | void hk_range_free(HkRange *range); 27 | void hk_range_release(HkRange *range); 28 | void hk_range_print(HkRange *range); 29 | bool hk_range_equal(HkRange *range1, HkRange *range2); 30 | int hk_range_compare(HkRange *range1, HkRange *range2); 31 | HkIterator *hk_range_new_iterator(HkRange *range); 32 | 33 | #endif // HK_RANGE_H 34 | -------------------------------------------------------------------------------- /include/hook/stack.h: -------------------------------------------------------------------------------- 1 | // 2 | // stack.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_STACK_H 12 | #define HK_STACK_H 13 | 14 | #include "memory.h" 15 | 16 | #define HkStack(T) \ 17 | struct { \ 18 | T *base; \ 19 | T *top; \ 20 | T *limit; \ 21 | } 22 | 23 | #define hk_stack_init(stk, sz) \ 24 | do { \ 25 | size_t _size = sizeof(*(stk)->base) * (sz); \ 26 | void *base = hk_allocate(_size); \ 27 | (stk)->base = base; \ 28 | (stk)->top = &(stk)->base[-1]; \ 29 | (stk)->limit = &(stk)->base[(sz) - 1]; \ 30 | } while (0) 31 | 32 | #define hk_stack_deinit(stk) \ 33 | do { \ 34 | hk_free((stk)->base); \ 35 | } while (0) 36 | 37 | #define hk_stack_is_empty(stk) ((stk)->top == &(stk)->base[-1]) 38 | 39 | #define hk_stack_is_full(stk) ((stk)->top == (stk)->limit) 40 | 41 | #define hk_stack_get(stk, i) ((stk)->top[- (i)]) 42 | 43 | #define hk_stack_set(stk, i, d) \ 44 | do { \ 45 | (stk)->top[- (i)] = (d); \ 46 | } while (0) 47 | 48 | #define hk_stack_push(stk, d) \ 49 | do { \ 50 | ++(stk)->top; \ 51 | (stk)->top[0] = (d); \ 52 | } while (0) 53 | 54 | #define hk_stack_pop(stk) \ 55 | do { \ 56 | --(stk)->top; \ 57 | } while (0) 58 | 59 | #endif // HK_STACK_H 60 | -------------------------------------------------------------------------------- /include/hook/string.h: -------------------------------------------------------------------------------- 1 | // 2 | // string.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_STRING_H 12 | #define HK_STRING_H 13 | 14 | #include "array.h" 15 | 16 | #define HK_STRING_MIN_CAPACITY (1 << 3) 17 | 18 | #define hk_string_is_empty(s) (!(s)->length) 19 | #define hk_string_get_char(s, i) ((s)->chars[(i)]) 20 | 21 | #define hk_string_inplace_clear(s) do \ 22 | { \ 23 | (s)->length = 0; \ 24 | (s)->hash = -1; \ 25 | } while (0) 26 | 27 | typedef struct 28 | { 29 | HK_OBJECT_HEADER 30 | int capacity; 31 | int length; 32 | char *chars; 33 | int64_t hash; 34 | } HkString; 35 | 36 | HkString *hk_string_new(void); 37 | HkString *hk_string_new_with_capacity(int minCapacity); 38 | HkString *hk_string_from_chars(int length, const char *chars); 39 | HkString *hk_string_from_stream(FILE *stream, const char delim); 40 | void hk_string_ensure_capacity(HkString *str, int minCapacity); 41 | void hk_string_free(HkString *str); 42 | void hk_string_release(HkString *str); 43 | HkString *hk_string_copy(HkString *str); 44 | HkString *hk_string_concat(HkString *str1, HkString *str2); 45 | void hk_string_inplace_concat_char(HkString *dest, char c); 46 | void hk_string_inplace_concat_chars(HkString *dest, int length, const char *chars); 47 | void hk_string_inplace_concat(HkString *dest, HkString *src); 48 | int hk_string_index_of_chars(HkString *str, int length, const char *chars); 49 | int hk_string_index_of(HkString *str, HkString *sub); 50 | HkString *hk_string_replace_all(HkString *str, HkString *sub1, HkString *sub2); 51 | HkString *hk_string_slice(HkString *str, int start, int stop); 52 | HkArray *hk_string_split(HkString *str, HkString *sep); 53 | void hk_string_print(HkString *str, bool quoted); 54 | uint32_t hk_string_hash(HkString *str); 55 | bool hk_string_equal(HkString *str1, HkString *str2); 56 | int hk_string_compare(HkString *str1, HkString *str2); 57 | HkString *hk_string_lower(HkString *str); 58 | HkString *hk_string_upper(HkString *str); 59 | bool hk_string_trim(HkString *str, HkString **result); 60 | bool hk_string_starts_with(HkString *str1, HkString *str2); 61 | bool hk_string_ends_with(HkString *str1, HkString *str2); 62 | HkString *hk_string_reverse(HkString *str); 63 | void hk_string_serialize(HkString *str, FILE *stream); 64 | HkString *hk_string_deserialize(FILE *stream); 65 | 66 | #endif // HK_STRING_H 67 | -------------------------------------------------------------------------------- /include/hook/struct.h: -------------------------------------------------------------------------------- 1 | // 2 | // struct.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_STRUCT_H 12 | #define HK_STRUCT_H 13 | 14 | #include "string.h" 15 | 16 | #define HK_STRUCT_MIN_CAPACITY (1 << 3) 17 | #define HK_STRUCT_MAX_LOAD_FACTOR 0.75 18 | 19 | #define hk_instance_get_field(inst, i) ((inst)->values[(i)]) 20 | 21 | typedef struct 22 | { 23 | HkString *name; 24 | int index; 25 | } HkField; 26 | 27 | typedef struct 28 | { 29 | HK_OBJECT_HEADER 30 | int capacity; 31 | int mask; 32 | int length; 33 | HkString *name; 34 | HkField *fields; 35 | HkField **table; 36 | } HkStruct; 37 | 38 | typedef struct 39 | { 40 | HK_OBJECT_HEADER 41 | HkStruct *ztruct; 42 | HkValue values[1]; 43 | } HkInstance; 44 | 45 | HkStruct *hk_struct_new(HkString *name); 46 | void hk_struct_free(HkStruct *ztruct); 47 | void hk_struct_release(HkStruct *ztruct); 48 | int hk_struct_index_of(HkStruct *ztruct, HkString *name); 49 | bool hk_struct_define_field(HkStruct *ztruct, HkString *name); 50 | bool hk_struct_equal(HkStruct *ztruct1, HkStruct *ztruct2); 51 | HkInstance *hk_instance_new(HkStruct *ztruct); 52 | void hk_instance_free(HkInstance *inst); 53 | void hk_instance_release(HkInstance *inst); 54 | HkInstance *hk_instance_set_field(HkInstance *inst, int index, HkValue value); 55 | void hk_instance_inplace_set_field(HkInstance *inst, int index, HkValue value); 56 | void hk_instance_print(HkInstance *inst); 57 | bool hk_instance_equal(HkInstance *inst1, HkInstance *inst2); 58 | 59 | #endif // HK_STRUCT_H 60 | -------------------------------------------------------------------------------- /include/hook/userdata.h: -------------------------------------------------------------------------------- 1 | // 2 | // userdata.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_USERDATA_H 12 | #define HK_USERDATA_H 13 | 14 | #include "value.h" 15 | 16 | #define HK_USERDATA_HEADER HK_OBJECT_HEADER \ 17 | void (*deinit)(struct HkUserdata *); 18 | 19 | typedef struct HkUserdata 20 | { 21 | HK_USERDATA_HEADER 22 | } HkUserdata; 23 | 24 | void hk_userdata_init(HkUserdata *udata, void (*deinit)(HkUserdata *)); 25 | void hk_userdata_free(HkUserdata *udata); 26 | 27 | #endif // HK_USERDATA_H 28 | -------------------------------------------------------------------------------- /include/hook/utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // utils.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_UTILS_H 12 | #define HK_UTILS_H 13 | 14 | #include 15 | #include 16 | 17 | #define HK_LOAD_MODULE_HANDLER_PREFIX "load_" 18 | 19 | #ifdef _WIN32 20 | #define HK_LOAD_MODULE_HANDLER(n) void __declspec(dllexport) __stdcall load_##n(HkVM *vm) 21 | #else 22 | #define HK_LOAD_MODULE_HANDLER(n) void load_##n(HkVM *vm) 23 | #endif 24 | 25 | #define hk_assert(cond, msg) do \ 26 | { \ 27 | if (!(cond)) \ 28 | { \ 29 | fprintf(stderr, "assertion failed: %s\n at %s() in %s:%d\n", \ 30 | (msg), __func__, __FILE__, __LINE__); \ 31 | exit(EXIT_FAILURE); \ 32 | } \ 33 | } while(0) 34 | 35 | int hk_power_of_two_ceil(int n); 36 | void hk_ensure_path(const char *filename); 37 | bool hk_long_from_chars(long *result, const char *chars); 38 | bool hk_double_from_chars(double *result, const char *chars, bool strict); 39 | void hk_copy_cstring(char *dest, const char *src, int max_len); 40 | char *hk_duplicate_cstring(const char *str); 41 | 42 | #endif // HK_UTILS_H 43 | -------------------------------------------------------------------------------- /include/hook/vm.h: -------------------------------------------------------------------------------- 1 | // 2 | // vm.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef HK_VM_H 12 | #define HK_VM_H 13 | 14 | #include "callable.h" 15 | #include "range.h" 16 | #include "stack.h" 17 | #include "struct.h" 18 | #include "userdata.h" 19 | 20 | #define HK_VM_FLAG_NONE 0x00 21 | #define HK_VM_FLAG_NO_TRACE 0x01 22 | 23 | #define HK_VM_STACK_DEFAULT_SIZE (1 << 10) 24 | 25 | #define hk_vm_is_no_trace(s) ((s)->flags & HK_VM_FLAG_NO_TRACE) 26 | 27 | #define hk_vm_is_ok(s) ((s)->status == HK_VM_STATUS_OK) 28 | #define hk_vm_is_exit(s) ((s)->status == HK_VM_STATUS_EXIT) 29 | #define hk_vm_is_error(s) ((s)->status == HK_VM_STATUS_ERROR) 30 | 31 | #define hk_return_if_not_ok(s) do \ 32 | { \ 33 | if (!hk_vm_is_ok(s)) \ 34 | return; \ 35 | } while (0) 36 | 37 | typedef enum 38 | { 39 | HK_VM_STATUS_OK, 40 | HK_VM_STATUS_EXIT, 41 | HK_VM_STATUS_ERROR 42 | } HkSateStatus; 43 | 44 | typedef struct HkVM 45 | { 46 | HkStack(HkValue) vstk; 47 | int flags; 48 | HkSateStatus status; 49 | } HkVM; 50 | 51 | void hk_vm_init(HkVM *vm, int size); 52 | void hk_vm_deinit(HkVM *vm); 53 | void hk_vm_runtime_error(HkVM *vm, const char *fmt, ...); 54 | void hk_vm_check_argument_type(HkVM *vm, HkValue *args, int index, HkType type); 55 | void hk_vm_check_argument_types(HkVM *vm, HkValue *args, int index, int numTypes, HkType types[]); 56 | void hk_vm_check_argument_bool(HkVM *vm, HkValue *args, int index); 57 | void hk_vm_check_argument_number(HkVM *vm, HkValue *args, int index); 58 | void hk_vm_check_argument_int(HkVM *vm, HkValue *args, int index); 59 | void hk_vm_check_argument_string(HkVM *vm, HkValue *args, int index); 60 | void hk_vm_check_argument_range(HkVM *vm, HkValue *args, int index); 61 | void hk_vm_check_argument_array(HkVM *vm, HkValue *args, int index); 62 | void hk_vm_check_argument_struct(HkVM *vm, HkValue *args, int index); 63 | void hk_vm_check_argument_instance(HkVM *vm, HkValue *args, int index); 64 | void hk_vm_check_argument_iterator(HkVM *vm, HkValue *args, int index); 65 | void hk_vm_check_argument_callable(HkVM *vm, HkValue *args, int index); 66 | void hk_vm_check_argument_userdata(HkVM *vm, HkValue *args, int index); 67 | void hk_vm_push(HkVM *vm, HkValue val); 68 | void hk_vm_push_nil(HkVM *vm); 69 | void hk_vm_push_bool(HkVM *vm, bool data); 70 | void hk_vm_push_number(HkVM *vm, double data); 71 | void hk_vm_push_string(HkVM *vm, HkString *str); 72 | void hk_vm_push_string_from_chars(HkVM *vm, int length, const char *chars); 73 | void hk_vm_push_string_from_stream(HkVM *vm, FILE *stream, const char delim); 74 | void hk_vm_push_range(HkVM *vm, HkRange *range); 75 | void hk_vm_push_array(HkVM *vm, HkArray *arr); 76 | void hk_vm_push_struct(HkVM *vm, HkStruct *ztruct); 77 | void hk_vm_push_instance(HkVM *vm, HkInstance *inst); 78 | void hk_vm_push_iterator(HkVM *vm, HkIterator *it); 79 | void hk_vm_push_closure(HkVM *vm, HkClosure *cl); 80 | void hk_vm_push_native(HkVM *vm, HkNative *native); 81 | void hk_vm_push_new_native(HkVM *vm, const char *name, int arity, 82 | HkCallFn call); 83 | void hk_vm_push_userdata(HkVM *vm, HkUserdata *udata); 84 | void hk_vm_array(HkVM *vm, int length); 85 | void hk_vm_struct(HkVM *vm, int length); 86 | void hk_vm_instance(HkVM *vm, int numArgs); 87 | void hk_vm_construct(HkVM *vm, int length); 88 | void hk_vm_pop(HkVM *vm); 89 | void hk_vm_call(HkVM *vm, int numArgs); 90 | void hk_vm_compare(HkVM *vm, HkValue val1, HkValue val2, int *result); 91 | 92 | #endif // HK_VM_H 93 | -------------------------------------------------------------------------------- /scripts/benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | printf "Running benchmark..\n\n" 4 | 5 | prefix="benchmark/fib" 6 | n=5 7 | m=28 8 | 9 | echo "Hook" 10 | hook --version 11 | start=$(date +%s%N) 12 | hook "$prefix.hk" $n $m 13 | hook_elapsed=$((($(date +%s%N) - $start) / 1000000)) 14 | echo "" 15 | 16 | echo "Node.js" 17 | node --version 18 | start=$(date +%s%N) 19 | node "$prefix.js" $n $m 20 | nodejs_elapsed=$((($(date +%s%N) - $start) / 1000000)) 21 | echo "" 22 | 23 | echo "Lua" 24 | lua -v 25 | start=$(date +%s%N) 26 | lua "$prefix.lua" $n $m 27 | lua_elapsed=$((($(date +%s%N) - $start) / 1000000)) 28 | echo "" 29 | 30 | echo "PHP" 31 | php --version 32 | start=$(date +%s%N) 33 | php "$prefix.php" $n $m 34 | php_elapsed=$((($(date +%s%N) - $start) / 1000000)) 35 | echo "" 36 | 37 | echo "Python 3" 38 | python3 --version 39 | start=$(date +%s%N) 40 | python3 "$prefix.py" $n $m 41 | python3_elapsed=$((($(date +%s%N) - $start) / 1000000)) 42 | echo "" 43 | 44 | echo "Ruby" 45 | ruby --version 46 | start=$(date +%s%N) 47 | ruby "$prefix.rb" $n $m 48 | ruby_elapsed=$((($(date +%s%N) - $start) / 1000000)) 49 | echo "" 50 | 51 | printf "Hook | Node.js | Lua | PHP | Python 3 | Ruby\n"; 52 | echo "----------+----------+----------+----------+----------+----------"; 53 | fmt="%-7s | %-6s | %-6s | %-6s | %-6s | %s\n\n" 54 | printf "$fmt" "$hook_elapsed ms" "$nodejs_elapsed ms" "$lua_elapsed ms" "$php_elapsed ms" "$python3_elapsed ms" "$ruby_elapsed ms" 55 | -------------------------------------------------------------------------------- /scripts/build-and-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # This script is used to build Hook and install it into the system. 5 | # 6 | # Usage: 7 | # 8 | # build-and-install.sh [build_type] [with-extensions] [install_prefix] 9 | # 10 | # build_type: 11 | # 12 | # Debug (default) 13 | # Release 14 | # 15 | # Examples: 16 | # 17 | # build-and-install.sh 18 | # build-and-install.sh Release 19 | # build-and-install.sh Release with-extensions 20 | # build-and-install.sh Release without-extensions /usr/local 21 | #------------------------------------------------------------------------------ 22 | 23 | build_type="$1" 24 | with_extensions="$2" 25 | install_prefix="$3" 26 | 27 | source scripts/utils.sh 28 | 29 | cmake_build_and_install $build_type $with_extensions $install_prefix 30 | -------------------------------------------------------------------------------- /scripts/build-with-extensions.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build -DCMAKE_TOOLCHAIN_FILE=%HOMEDRIVE%%HOMEPATH%\vcpkg\scripts\buildsystems\vcpkg.cmake -DBUILD_EXTENSIONS=1 4 | cmake --build build --config Debug 5 | -------------------------------------------------------------------------------- /scripts/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build 4 | cmake --build build --config Debug 5 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # This script is used to build Hook. 5 | # 6 | # Usage: 7 | # 8 | # build.sh [build_type] [with-extensions] [install_prefix] 9 | # 10 | # build_type: 11 | # 12 | # Debug (default) 13 | # Release 14 | # 15 | # Examples: 16 | # 17 | # build.sh 18 | # build.sh Release 19 | # build.sh Release with-extensions 20 | # build.sh Release without-extensions /usr/local 21 | #------------------------------------------------------------------------------ 22 | 23 | build_type="$1" 24 | with_extensions="$2" 25 | install_prefix="$3" 26 | 27 | source scripts/utils.sh 28 | 29 | cmake_build $build_type $with_extensions $install_prefix 30 | -------------------------------------------------------------------------------- /scripts/clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rd /S /Q bin 2>nul 4 | rd /S /Q build 2>nul 5 | rd /S /Q lib 2>nul 6 | rd /S /Q package 2>nul 7 | -------------------------------------------------------------------------------- /scripts/clean.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -fr bin 4 | rm -fr build 5 | rm -fr lib 6 | rm -fr package 7 | -------------------------------------------------------------------------------- /scripts/install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem ------------------------------------------------------------------------------ 5 | rem Installation script for Hook 6 | rem ------------------------------------------------------------------------------ 7 | 8 | set BASE_URL=https://github.com/hook-lang/hook/releases/download 9 | set VERSION=0.1.0 10 | set ARCH=x64 11 | 12 | rem ------------------------------------------------------------------------------ 13 | rem Download and install 14 | rem ------------------------------------------------------------------------------ 15 | 16 | set base_name=hook-%VERSION%-windows-%ARCH% 17 | set dist_url=%BASE_URL%/%VERSION%/%base_name%.tar.gz 18 | set temp_file=%TEMP%\hook-dist.tar.gz 19 | 20 | echo "Downloading: %dist_url%" 21 | 22 | curl --proto =https --tlsv1.2 -f -L -o "%temp_file%" "%dist_url%" 23 | if errorlevel 1 ( 24 | echo "Unable to download: %dist_url%" 25 | goto end 26 | ) 27 | 28 | echo "Unpacking.." 29 | 30 | tar -xzf "%temp_file%" 31 | if errorlevel 1 ( 32 | echo "Extraction failed." 33 | goto end 34 | ) 35 | 36 | set home_dir=%SystemDrive%\hook 37 | 38 | echo "Installing to: %home_dir%" 39 | 40 | move %base_name% %home_dir% >nul 41 | 42 | echo "Cleaning up.." 43 | 44 | del /q "%temp_file%" 45 | 46 | rem ------------------------------------------------------------------------------ 47 | rem Setup the environment variable 48 | rem ------------------------------------------------------------------------------ 49 | 50 | echo "Setting the environment variable: HOOK_HOME" 51 | 52 | echo "%PATH%" | find "%home_dir%\bin">nul 53 | if not errorlevel 1 goto done 54 | 55 | where /q powershell 56 | if not errorlevel 1 ( 57 | 58 | set HOOK_HOME=%home_dir% 59 | powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "[Environment]::SetEnvironmentVariable('HOOK_HOME',\""%home_dir%\"",'User');" 60 | 61 | set semicolon=; 62 | if "%PATH:~-1%"==";" (set semicolon=) 63 | set "PATH=%PATH%%semicolon%%home_dir%\bin" 64 | powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "[Environment]::SetEnvironmentVariable('PATH',\""$([Environment]::GetEnvironmentVariable('PATH','User'))%semicolon%%home_dir%\bin\"",'User');" 65 | 66 | if not errorlevel 1 goto done 67 | ) 68 | 69 | echo "Please add %home_dir%\bin to your PATH environment variable." 70 | :done 71 | 72 | rem ------------------------------------------------------------------------------ 73 | rem End 74 | rem ------------------------------------------------------------------------------ 75 | 76 | echo "Install successful." 77 | echo "You can check the installation by running 'hook --version'." 78 | echo "Enjoy!" 79 | 80 | endlocal & ( 81 | set "HOOK_HOME=%HOOK_HOME%" 82 | set "PATH=%PATH%" 83 | ) 84 | 85 | :end 86 | -------------------------------------------------------------------------------- /scripts/pack-with-extensions.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build -DCMAKE_TOOLCHAIN_FILE=%HOMEDRIVE%%HOMEPATH%\vcpkg\scripts\buildsystems\vcpkg.cmake -DBUILD_EXTENSIONS=1 4 | cmake --build build --config Release 5 | cpack --config build\CPackConfig.cmake 6 | -------------------------------------------------------------------------------- /scripts/pack.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build 4 | cmake --build build --config Release 5 | cpack --config build\CPackConfig.cmake 6 | 7 | -------------------------------------------------------------------------------- /scripts/pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # This script is used to build a release version of Hook and pack it into a 5 | # tarball. 6 | # 7 | # Usage: 8 | # 9 | # pack.sh [with-extensions] 10 | # 11 | # Examples: 12 | # 13 | # pack.sh 14 | # pack.sh with-extensions 15 | #------------------------------------------------------------------------------ 16 | 17 | with_extensions="$1" 18 | 19 | source scripts/utils.sh 20 | 21 | cmake_build_and_pack Release $with_extensions 22 | -------------------------------------------------------------------------------- /scripts/release-with-extensions.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build -DCMAKE_TOOLCHAIN_FILE=%HOMEDRIVE%%HOMEPATH%\vcpkg\scripts\buildsystems\vcpkg.cmake -DBUILD_EXTENSIONS=1 4 | cmake --build build --config Release 5 | -------------------------------------------------------------------------------- /scripts/release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake -B build 4 | cmake --build build --config Release 5 | -------------------------------------------------------------------------------- /scripts/test.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo "Running tests.." 4 | 5 | set /a n=0 6 | for %%f in (tests\*.hk) do ( 7 | bin\hook %%f 8 | set /a n=n+1 9 | ) 10 | 11 | echo "%n% test(s)" 12 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Running tests.." 4 | 5 | n=0 6 | for f in tests/*.hk ; do 7 | bin/hook $f 8 | n=$(($n + 1)) 9 | done 10 | 11 | echo "$n test(s)" 12 | -------------------------------------------------------------------------------- /scripts/utils.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DEFAULT_BUILD_TYPE="Debug" 4 | 5 | cmake_build() { 6 | build_type="$1" 7 | with_extensions="$2" 8 | install_prefix="$3" 9 | 10 | if [ -z "$build_type" ]; then 11 | build_type="$DEFAULT_BUILD_TYPE" 12 | fi 13 | if [ "$with_extensions" == "with-extensions" ]; then 14 | with_extensions="-DBUILD_EXTENSIONS=1" 15 | else 16 | with_extensions="" 17 | fi 18 | 19 | if [ -z "$install_prefix" ]; then 20 | cmake -B build -DCMAKE_BUILD_TYPE=$build_type $with_extensions 21 | else 22 | cmake -B build -DCMAKE_BUILD_TYPE=$build_type $with_extensions -DCMAKE_INSTALL_PREFIX=$install_prefix 23 | fi 24 | 25 | cmake --build build 26 | } 27 | 28 | cmake_build_and_install() { 29 | build_type="$1" 30 | with_extensions="$2" 31 | install_prefix="$3" 32 | cmake_build $build_type $with_extensions $install_prefix 33 | cmake --install build 34 | } 35 | 36 | cmake_build_and_pack() { 37 | build_type="$1" 38 | with_extensions="$2" 39 | cmake_build $build_type $with_extensions 40 | cpack --config build/CPackConfig.cmake 41 | } 42 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # CMakeLists.txt (Libraries) 3 | # ------------------------------------------------------------------------------ 4 | 5 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 6 | 7 | if(MSVC) 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${LIBRARY_DIR}) 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${LIBRARY_DIR}) 10 | endif() 11 | 12 | if(NOT MSVC) 13 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_DIR}) 14 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_DIR}) 15 | endif() 16 | 17 | set(SOURCES 18 | "array.c" 19 | "builtin.c" 20 | "callable.c" 21 | "chunk.c" 22 | "utils.c" 23 | "compiler.c" 24 | "dump.c" 25 | "iterable.c" 26 | "iterator.c" 27 | "lexer.c" 28 | "memory.c" 29 | "module.c" 30 | "range.c" 31 | "record.c" 32 | "string.c" 33 | "struct.c" 34 | "userdata.c" 35 | "value.c" 36 | "vm.c" 37 | ) 38 | 39 | add_library(${STATIC_LIB_TARGET} STATIC ${SOURCES}) 40 | add_library(${SHARED_LIB_TARGET} SHARED ${SOURCES}) 41 | 42 | set_target_properties(${STATIC_LIB_TARGET} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) 43 | set_target_properties(${SHARED_LIB_TARGET} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) 44 | 45 | if(NOT MSVC) 46 | target_link_libraries(${STATIC_LIB_TARGET} m) 47 | target_link_libraries(${STATIC_LIB_TARGET} dl) 48 | target_link_libraries(${SHARED_LIB_TARGET} m) 49 | target_link_libraries(${SHARED_LIB_TARGET} dl) 50 | endif() 51 | -------------------------------------------------------------------------------- /src/builtin.h: -------------------------------------------------------------------------------- 1 | // 2 | // builtin.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef BUILTIN_H 12 | #define BUILTIN_H 13 | 14 | #include "hook/vm.h" 15 | 16 | void load_globals(HkVM *vm); 17 | int num_globals(void); 18 | int lookup_global(int length, char *chars); 19 | 20 | #endif // BUILTIN_H 21 | -------------------------------------------------------------------------------- /src/iterable.c: -------------------------------------------------------------------------------- 1 | // 2 | // iterable.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "hook/iterable.h" 12 | #include "hook/array.h" 13 | #include "hook/range.h" 14 | 15 | HkIterator *hk_new_iterator(HkValue val) 16 | { 17 | if (!hk_is_iterable(val)) 18 | return NULL; 19 | if (hk_is_range(val)) 20 | return hk_range_new_iterator(hk_as_range(val)); 21 | return hk_array_new_iterator(hk_as_array(val)); 22 | } 23 | -------------------------------------------------------------------------------- /src/iterator.c: -------------------------------------------------------------------------------- 1 | // 2 | // iterator.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "hook/iterator.h" 12 | #include "hook/memory.h" 13 | 14 | void hk_iterator_init(HkIterator *it, void (*deinit)(HkIterator *), 15 | bool (*isValid)(HkIterator *), HkValue (*getCurrent)(HkIterator *), 16 | HkIterator *(*next)(HkIterator *), void (*inplaceNext)(HkIterator *)) 17 | { 18 | it->refCount = 0; 19 | it->deinit = deinit; 20 | it->isValid = isValid; 21 | it->getCurrent = getCurrent; 22 | it->next = next; 23 | it->inplaceNext = inplaceNext; 24 | } 25 | 26 | void hk_iterator_free(HkIterator *it) 27 | { 28 | if (it->deinit) 29 | it->deinit(it); 30 | hk_free(it); 31 | } 32 | 33 | void hk_iterator_release(HkIterator *it) 34 | { 35 | hk_decr_ref(it); 36 | if (hk_is_unreachable(it)) 37 | hk_iterator_free(it); 38 | } 39 | 40 | bool hk_iterator_is_valid(HkIterator *it) 41 | { 42 | return it->isValid(it); 43 | } 44 | 45 | HkValue hk_iterator_get_current(HkIterator *it) 46 | { 47 | return it->getCurrent(it); 48 | } 49 | 50 | HkIterator *hk_iterator_next(HkIterator *it) 51 | { 52 | return it->next(it); 53 | } 54 | 55 | void hk_iterator_inplace_next(HkIterator *it) 56 | { 57 | it->inplaceNext(it); 58 | } 59 | -------------------------------------------------------------------------------- /src/lexer.h: -------------------------------------------------------------------------------- 1 | // 2 | // lexer.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef LEXER_H 12 | #define LEXER_H 13 | 14 | #include "hook/string.h" 15 | 16 | typedef enum 17 | { 18 | TOKEN_KIND_EOF, TOKEN_KIND_DOTDOT, TOKEN_KIND_DOT, TOKEN_KIND_COMMA, 19 | TOKEN_KIND_COLON, TOKEN_KIND_SEMICOLON, TOKEN_KIND_LPAREN, TOKEN_KIND_RPAREN, 20 | TOKEN_KIND_LBRACKET, TOKEN_KIND_RBRACKET, TOKEN_KIND_LBRACE, TOKEN_KIND_RBRACE, 21 | TOKEN_KIND_PIPEEQ, TOKEN_KIND_PIPEPIPE, TOKEN_KIND_PIPE, TOKEN_KIND_CARETEQ, 22 | TOKEN_KIND_CARET, TOKEN_KIND_AMPEQ, TOKEN_KIND_AMPAMP, TOKEN_KIND_AMP, 23 | TOKEN_KIND_ARROW, TOKEN_KIND_EQEQ, TOKEN_KIND_EQ, TOKEN_KIND_BANGEQ, 24 | TOKEN_KIND_BANG, TOKEN_KIND_GTEQ, TOKEN_KIND_GTGTEQ, TOKEN_KIND_GTGT, 25 | TOKEN_KIND_GT, TOKEN_KIND_LTEQ, TOKEN_KIND_LTLTEQ, TOKEN_KIND_LTLT, 26 | TOKEN_KIND_LT, TOKEN_KIND_PLUSEQ, TOKEN_KIND_PLUSPLUS, TOKEN_KIND_PLUS, 27 | TOKEN_KIND_DASHEQ, TOKEN_KIND_DASHDASH, TOKEN_KIND_DASH, TOKEN_KIND_STAREQ, 28 | TOKEN_KIND_STAR, TOKEN_KIND_SLASHEQ, TOKEN_KIND_SLASH, TOKEN_KIND_TILDESLASHEQ, 29 | TOKEN_KIND_TILDESLASH, TOKEN_KIND_TILDE, TOKEN_KIND_PERCENTEQ, TOKEN_KIND_PERCENT, 30 | TOKEN_KIND_INT, TOKEN_KIND_FLOAT, TOKEN_KIND_STRING, TOKEN_KIND_UNDERSCORE_KW, 31 | TOKEN_KIND_AS_KW, TOKEN_KIND_BREAK_KW, TOKEN_KIND_CONTINUE_KW, TOKEN_KIND_DEL_KW, 32 | TOKEN_KIND_DO_KW, TOKEN_KIND_ELSE_KW, TOKEN_KIND_FALSE_KW, TOKEN_KIND_FN_KW, 33 | TOKEN_KIND_FOR_KW, TOKEN_KIND_FOREACH_KW, TOKEN_KIND_FROM_KW, TOKEN_KIND_IF_KW, 34 | TOKEN_KIND_IFBANG_KW, TOKEN_KIND_IMPORT_KW, TOKEN_KIND_IN_KW, TOKEN_KIND_LET_KW, 35 | TOKEN_KIND_LOOP_KW, TOKEN_KIND_MATCH_KW, TOKEN_KIND_NIL_KW, TOKEN_KIND_RETURN_KW, 36 | TOKEN_KIND_STRUCT_KW, TOKEN_KIND_TRUE_KW, TOKEN_KIND_VAR_KW, TOKEN_KIND_WHILE_KW, 37 | TOKEN_KIND_WHILEBANG_KW, TOKEN_KIND_NAME 38 | } TokenKind; 39 | 40 | typedef struct 41 | { 42 | TokenKind kind; 43 | int line; 44 | int col; 45 | int length; 46 | char *start; 47 | } Token; 48 | 49 | typedef struct 50 | { 51 | HkString *file; 52 | HkString *source; 53 | char *pos; 54 | int line; 55 | int col; 56 | Token token; 57 | } Lexer; 58 | 59 | void lexer_init(Lexer *lex, HkString *file, HkString *source); 60 | void lexer_deinit(Lexer *lex); 61 | void lexer_next_token(Lexer *lex); 62 | 63 | #endif // LEXER_H 64 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | // 2 | // memory.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "hook/memory.h" 12 | #include 13 | 14 | void *hk_allocate(size_t size) 15 | { 16 | return malloc(size); 17 | } 18 | 19 | void *hk_reallocate(void *ptr, size_t size) 20 | { 21 | return realloc(ptr, size); 22 | } 23 | 24 | void hk_free(void *ptr) 25 | { 26 | free(ptr); 27 | } 28 | -------------------------------------------------------------------------------- /src/module.h: -------------------------------------------------------------------------------- 1 | // 2 | // module.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef MODULE_H 12 | #define MODULE_H 13 | 14 | #include "hook/vm.h" 15 | 16 | void module_cache_init(void); 17 | void module_cache_deinit(void); 18 | void module_load(HkVM *vm, HkString *currFile); 19 | 20 | #endif // MODULE_H 21 | -------------------------------------------------------------------------------- /src/record.c: -------------------------------------------------------------------------------- 1 | // 2 | // record.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "record.h" 12 | #include "hook/memory.h" 13 | #include "hook/utils.h" 14 | 15 | static inline RecordEntry *allocate_entries(int capacity); 16 | static inline void grow(Record *rec); 17 | 18 | static inline RecordEntry *allocate_entries(int capacity) 19 | { 20 | RecordEntry *entries = (RecordEntry *) hk_allocate(sizeof(*entries) * capacity); 21 | for (int i = 0; i < capacity; ++i) 22 | entries[i].key = NULL; 23 | return entries; 24 | } 25 | 26 | static inline void grow(Record *rec) 27 | { 28 | int length = rec->length; 29 | if (length / RECORD_MAX_LOAD_FACTOR <= rec->capacity) 30 | return; 31 | int capacity = rec->capacity << 1; 32 | int mask = capacity - 1; 33 | RecordEntry *entries = allocate_entries(capacity); 34 | for (int i = 0, j = 0; i < rec->capacity && j < length; ++i) 35 | { 36 | RecordEntry *entry = &rec->entries[i]; 37 | HkString *key = entry->key; 38 | if (!key) 39 | continue; 40 | entries[key->hash & mask] = rec->entries[i]; 41 | ++j; 42 | } 43 | hk_free(rec->entries); 44 | rec->entries = entries; 45 | rec->capacity = capacity; 46 | rec->mask = mask; 47 | } 48 | 49 | void record_init(Record *rec, int minCapacity) 50 | { 51 | int capacity = minCapacity < RECORD_MIN_CAPACITY ? RECORD_MIN_CAPACITY : minCapacity; 52 | capacity = hk_power_of_two_ceil(capacity); 53 | rec->capacity = capacity; 54 | rec->mask = capacity - 1; 55 | rec->length = 0; 56 | rec->entries = allocate_entries(capacity); 57 | } 58 | 59 | void record_deinit(Record *rec) 60 | { 61 | RecordEntry *entries = rec->entries; 62 | for (int i = 0, j = 0; i < rec->capacity && j < rec->length; ++i) 63 | { 64 | RecordEntry *entry = &entries[i]; 65 | HkString *key = entry->key; 66 | if (!key) 67 | continue; 68 | hk_string_release(key); 69 | hk_value_release(entry->value); 70 | ++j; 71 | } 72 | hk_free(rec->entries); 73 | } 74 | 75 | RecordEntry *record_get_entry(Record *rec, HkString *key) 76 | { 77 | int mask = rec->mask; 78 | RecordEntry *entries = rec->entries; 79 | int index = hk_string_hash(key) & mask; 80 | for (;;) 81 | { 82 | RecordEntry *entry = &entries[index]; 83 | if (!entry->key) 84 | break; 85 | if (hk_string_equal(key, entry->key)) 86 | return entry; 87 | index = (index + 1) & mask; 88 | } 89 | return NULL; 90 | } 91 | 92 | void record_inplace_put(Record *rec, HkString *key, HkValue value) 93 | { 94 | int mask = rec->mask; 95 | RecordEntry *entries = rec->entries; 96 | int index = hk_string_hash(key) & mask; 97 | for (;;) 98 | { 99 | RecordEntry *entry = &entries[index]; 100 | if (!entry->key) 101 | { 102 | hk_incr_ref(key); 103 | hk_value_incr_ref(value); 104 | entry->key = key; 105 | entry->value = value; 106 | ++rec->length; 107 | grow(rec); 108 | return; 109 | } 110 | if (hk_string_equal(key, entry->key)) 111 | { 112 | hk_value_incr_ref(value); 113 | hk_value_decr_ref(entry->value); 114 | entry->value = value; 115 | return; 116 | } 117 | index = (index + 1) & mask; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/record.h: -------------------------------------------------------------------------------- 1 | // 2 | // record.h 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #ifndef RECORD_H 12 | #define RECORD_H 13 | 14 | #include "hook/string.h" 15 | 16 | #define RECORD_MIN_CAPACITY (1 << 3) 17 | #define RECORD_MAX_LOAD_FACTOR 0.75 18 | 19 | typedef struct 20 | { 21 | HkString *key; 22 | HkValue value; 23 | } RecordEntry; 24 | 25 | typedef struct 26 | { 27 | int capacity; 28 | int mask; 29 | int length; 30 | RecordEntry *entries; 31 | } Record; 32 | 33 | void record_init(Record *rec, int minCapacity); 34 | void record_deinit(Record *rec); 35 | RecordEntry *record_get_entry(Record *rec, HkString *key); 36 | void record_inplace_put(Record *rec, HkString *key, HkValue value); 37 | 38 | #endif // RECORD_H 39 | -------------------------------------------------------------------------------- /src/userdata.c: -------------------------------------------------------------------------------- 1 | // 2 | // userdata.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "hook/userdata.h" 12 | #include "hook/memory.h" 13 | 14 | void hk_userdata_init(HkUserdata *udata, void (*deinit)(HkUserdata *)) 15 | { 16 | udata->refCount = 0; 17 | udata->deinit = deinit; 18 | } 19 | 20 | void hk_userdata_free(HkUserdata *udata) 21 | { 22 | if (udata->deinit) 23 | udata->deinit(udata); 24 | hk_free(udata); 25 | } 26 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // utils.c 3 | // 4 | // Copyright 2021 The Hook Programming Language Authors. 5 | // 6 | // This file is part of the Hook project. 7 | // For detailed license information, please refer to the LICENSE file 8 | // located in the root directory of this project. 9 | // 10 | 11 | #include "hook/utils.h" 12 | #include 13 | #include 14 | #include 15 | #include "hook/memory.h" 16 | 17 | #ifdef _WIN32 18 | #include 19 | #include 20 | #else 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef __linux__ 26 | #include 27 | #endif 28 | 29 | #ifdef __APPLE__ 30 | #include 31 | #endif 32 | 33 | #ifdef _WIN32 34 | #define PATH_MAX MAX_PATH 35 | #endif 36 | 37 | static void make_directory(char *path); 38 | 39 | static void make_directory(char *path) 40 | { 41 | char *sep = strrchr(path, '/'); 42 | if (sep) 43 | { 44 | *sep = '\0'; 45 | make_directory(path); 46 | *sep = '/'; 47 | } 48 | #ifdef _WIN32 49 | _mkdir(path); 50 | #else 51 | mkdir(path, 0777); 52 | #endif 53 | } 54 | 55 | int hk_power_of_two_ceil(int n) 56 | { 57 | --n; 58 | n |= n >> 1; 59 | n |= n >> 2; 60 | n |= n >> 4; 61 | n |= n >> 8; 62 | n |= n >> 16; 63 | ++n; 64 | return n; 65 | } 66 | 67 | void hk_ensure_path(const char *filename) 68 | { 69 | char *sep = strrchr(filename, '/'); 70 | if (sep) 71 | { 72 | char path[PATH_MAX + 1]; 73 | hk_copy_cstring(path, filename, PATH_MAX); 74 | path[sep - filename] = '\0'; 75 | make_directory(path); 76 | } 77 | } 78 | 79 | bool hk_long_from_chars(long *result, const char *chars) 80 | { 81 | errno = 0; 82 | char *end = (char *) chars; 83 | long _result = strtol(chars, &end, 10); 84 | if (errno == ERANGE) 85 | return false; 86 | if (*end) 87 | return false; 88 | *result = _result; 89 | return true; 90 | } 91 | 92 | bool hk_double_from_chars(double *result, const char *chars, bool strict) 93 | { 94 | errno = 0; 95 | char *end; 96 | double _result = strtod(chars, &end); 97 | if (errno == ERANGE) 98 | return false; 99 | if (strict && *end) 100 | return false; 101 | *result = _result; 102 | return true; 103 | } 104 | 105 | void hk_copy_cstring(char *dest, const char *src, int max_len) 106 | { 107 | #ifdef _WIN32 108 | strncpy_s(dest, max_len + 1, src, _TRUNCATE); 109 | #else 110 | strncpy(dest, src, max_len); 111 | dest[max_len] = '\0'; 112 | #endif 113 | } 114 | 115 | char *hk_duplicate_cstring(const char *str) 116 | { 117 | int length = (int) strnlen(str, INT_MAX); 118 | char *_str = (char *) hk_allocate(length + 1); 119 | memcpy(_str, str, length); 120 | _str[length] = '\0'; 121 | return _str; 122 | } 123 | -------------------------------------------------------------------------------- /tests/anonymous_function_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let sum = |a, b| { 3 | return a + b; 4 | }; 5 | 6 | println(sum(1, 2)); 7 | -------------------------------------------------------------------------------- /tests/arithmetic_assignment_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var a; 3 | a = 1; 4 | a += 1; 5 | a -= 1; 6 | a *= 1; 7 | a /= 1; 8 | a ~/= 1; 9 | a %= 1; 10 | a++; 11 | a--; 12 | 13 | var b = []; 14 | b[] = 1; 15 | b[0] += 1; 16 | b[0] -= 1; 17 | b[0] *= 1; 18 | b[0] /= 1; 19 | b[0] ~/= 1; 20 | b[0] %= 1; 21 | b[0]++; 22 | b[0]--; 23 | 24 | var c = [[]]; 25 | c[0][] = 1; 26 | c[0][0] += 1; 27 | c[0][0] -= 1; 28 | c[0][0] *= 1; 29 | c[0][0] /= 1; 30 | c[0][0] ~/= 1; 31 | c[0][0] %= 1; 32 | c[0][0]++; 33 | c[0][0]--; 34 | -------------------------------------------------------------------------------- /tests/arithmetic_expression_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(123 + 1.23); 3 | println(123 - 1.23); 4 | println(123 * 1.23); 5 | println(123 / 1.23); 6 | println(3 ~/ 1.23); 7 | println(123 % 12.3); 8 | println(-123); 9 | println(-1.23); 10 | println(-(-123)); 11 | println(123 + 1.23 * 4); 12 | println((123 + 1.23) * 4); 13 | -------------------------------------------------------------------------------- /tests/array_add_element_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var arr1 = []; 3 | arr1[] = "foo"; 4 | println(arr1); 5 | 6 | var arr2 = [[]]; 7 | arr2[0][] = "foo"; 8 | println(arr2); 9 | 10 | var arr3 = [[[]]]; 11 | arr3[0][0][] = "foo"; 12 | println(arr3); 13 | 14 | var arr4 = [[1, 2, 3]]; 15 | arr4[0][] = 4; 16 | println(arr4); 17 | -------------------------------------------------------------------------------- /tests/array_compare_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([] > []); 3 | println([] < []); 4 | println([1] > [1]); 5 | println([1] < [1]); 6 | println([1] > [1, 2]); 7 | println([1] < [1, 2]); 8 | println([1, 2] > [1]); 9 | println([1, 2] < [1]); 10 | println([1, 2] > [1, 2]); 11 | println([1, 2] < [1, 2]); 12 | println([1, 2] > [2, 1]); 13 | println([1, 2] < [2, 1]); 14 | let a = ["foo"]; 15 | println(a > a); 16 | println(a < a); 17 | -------------------------------------------------------------------------------- /tests/array_concatenation_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([] + ["foo"]); 3 | println(["foo"] + []); 4 | println(["foo", "bar"] + ["baz"]); 5 | let arr = ["foo", "bar"]; 6 | println(arr + ["baz", "qux"]); 7 | -------------------------------------------------------------------------------- /tests/array_delete_element_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var arr = [1, 2, 3, ["foo", "bar", "baz"]]; 3 | del arr[1]; 4 | println(arr); 5 | 6 | del arr[2][1]; 7 | println(arr); 8 | -------------------------------------------------------------------------------- /tests/array_difference_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([] - ["foo"]); 3 | println(["foo"] - []); 4 | println(["foo", "bar", "baz"] - ["bar"]); 5 | let arr = ["foo", "bar", "baz", "bar", "qux"]; 6 | println(arr - ["bar", "baz"]); 7 | -------------------------------------------------------------------------------- /tests/array_equal_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([] == []); 3 | println([1] == [1]); 4 | println([1] == [1, 2]); 5 | println([1, 2] == [1]); 6 | println([1, 2] == [1, 2]); 7 | println([1, 2] == [2, 1]); 8 | let a = ["foo"]; 9 | println(a == a); 10 | -------------------------------------------------------------------------------- /tests/array_get_element_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let arr1 = ["foo", "bar", "baz"]; 3 | println(arr1[0]); 4 | println(arr1[1]); 5 | println(arr1[2]); 6 | 7 | let arr2 = [["foo", "bar"]]; 8 | println(arr2[0][1]); 9 | -------------------------------------------------------------------------------- /tests/array_initializer_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([]); 3 | println([123]); 4 | println([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 5 | -------------------------------------------------------------------------------- /tests/array_resize_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var arr = []; 3 | for (var i = 1; i <= 100; i++) { 4 | arr[] = i; 5 | } 6 | println(arr[99]); 7 | -------------------------------------------------------------------------------- /tests/array_set_element_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var arr1 = ["foo"]; 3 | arr1[0] = "bar"; 4 | println(arr1); 5 | 6 | var arr2 = [["foo"]]; 7 | arr2[0][0] = "bar"; 8 | println(arr2); 9 | 10 | var arr3 = [[["foo"]]]; 11 | arr3[0][0][0] = "bar"; 12 | println(arr3); 13 | 14 | var arr4 = [["foo", "bar", "baz"]]; 15 | arr4[0][1] = "qux"; 16 | println(arr4); 17 | -------------------------------------------------------------------------------- /tests/array_slice_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let arr = ["foo", "bar", "baz"]; 3 | 4 | assert(arr[0 .. 0] == ["foo"], "range 0 .. 0"); 5 | assert(arr[1 .. 1] == ["bar"], "range 1 .. 1"); 6 | assert(arr[2 .. 2] == ["baz"], "range 2 .. 2"); 7 | 8 | assert(arr[0 .. 1] == ["foo", "bar"], "range 0 .. 1"); 9 | assert(arr[0 .. 2] == ["foo", "bar", "baz"], "range 0 .. 2"); 10 | assert(arr[0 .. 3] == ["foo", "bar", "baz"], "range 0 .. 3"); 11 | 12 | assert(arr[1 .. 0] == [], "range 1 .. 0"); 13 | assert(arr[2 .. 0] == [], "range 2 .. 0"); 14 | assert(arr[3 .. 0] == [], "range 3 .. 0"); 15 | 16 | assert(arr[-1 .. 3] == ["foo", "bar", "baz"], "range -1 .. 3"); 17 | assert(arr[3 .. -1] == [], "range 3 .. -1"); 18 | assert(arr[-2 .. -1] == [], "range -2 .. -1"); 19 | assert(arr[3 .. 4] == [], "range 3 .. 4"); 20 | -------------------------------------------------------------------------------- /tests/bitwise_shift_assignment_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var a = 0; 3 | a |= 1; 4 | a ^= 1; 5 | a &= 1; 6 | a <<= 1; 7 | a >>= 1; 8 | 9 | var b = [0]; 10 | b[0] |= 1; 11 | b[0] ^= 1; 12 | b[0] &= 1; 13 | b[0] <<= 1; 14 | b[0] >>= 1; 15 | 16 | var c = [[0]]; 17 | c[0][0] |= 1; 18 | c[0][0] ^= 1; 19 | c[0][0] &= 1; 20 | c[0][0] <<= 1; 21 | c[0][0] >>= 1; 22 | -------------------------------------------------------------------------------- /tests/bitwise_shift_expression_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(0 | 0); 3 | println(0 | 15); 4 | println(15 | 0); 5 | println(15 | 15); 6 | 7 | println(0 ^ 0); 8 | println(0 ^ 15); 9 | println(15 ^ 0); 10 | println(15 ^ 15); 11 | 12 | println(0 & 0); 13 | println(0 & 15); 14 | println(15 & 0); 15 | println(15 & 15); 16 | 17 | println(0 << 0); 18 | println(0 << 3); 19 | println(1 << 0); 20 | println(1 << 3); 21 | 22 | println(0 >> 0); 23 | println(0 >> 3); 24 | println(1 >> 0); 25 | println(8 >> 3); 26 | 27 | println(~0); 28 | println(~15); 29 | -------------------------------------------------------------------------------- /tests/branching_statements_and_expressions_test.hk: -------------------------------------------------------------------------------- 1 | 2 | if (true) { 3 | println("foo"); 4 | } 5 | 6 | if (true) { 7 | println("foo"); 8 | } else { 9 | println("bar"); 10 | } 11 | 12 | if (false) { 13 | println("foo"); 14 | } else { 15 | println("bar"); 16 | } 17 | 18 | println(if (true) "foo" else "bar"); 19 | println(if (false) "foo" else "bar"); 20 | 21 | if! (true) { 22 | println("foo"); 23 | } 24 | 25 | if! (true) { 26 | println("foo"); 27 | } else { 28 | println("bar"); 29 | } 30 | 31 | if! (false) { 32 | println("foo"); 33 | } else { 34 | println("bar"); 35 | } 36 | 37 | println(if! (true) "foo" else "bar"); 38 | println(if! (false) "foo" else "bar"); 39 | -------------------------------------------------------------------------------- /tests/builtin_function_address_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(address(nil)); 3 | println(address(1)); 4 | println(address("foo")); 5 | println(address([1, 2, 3])); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_assert_test.hk: -------------------------------------------------------------------------------- 1 | 2 | assert(1, "ok"); 3 | assert(nil, "oops!"); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_bin_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(bin("414243")); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_cap_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(cap("foo")); 3 | println(cap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_chr_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(chr(102)); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_compare_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(compare(nil, nil)); 3 | println(compare(false, false)); 4 | println(compare(false, true)); 5 | println(compare(true, false)); 6 | println(compare(123, 123)); 7 | println(compare(123, 1.23)); 8 | println(compare(1.23, 123)); 9 | println(compare("foo", "foo")); 10 | println(compare("foo", "bar")); 11 | println(compare("bar", "foo")); 12 | -------------------------------------------------------------------------------- /tests/builtin_function_exit_test.hk: -------------------------------------------------------------------------------- 1 | 2 | exit(1); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_hex_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(hex("ABC")); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_is_array_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_array([])); 3 | println(is_array([1, 2, 3])); 4 | println(is_array(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_bool_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_bool(false)); 3 | println(is_bool(true)); 4 | println(is_bool(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_callable_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_callable(print)); 3 | println(is_callable(|| {})); 4 | println(is_callable(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_comparable_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_comparable(nil)); 3 | println(is_comparable(false)); 4 | println(is_comparable(1)); 5 | println(is_comparable(1 .. 10)); 6 | println(is_comparable("foo")); 7 | println(is_comparable([1,2,3])); 8 | println(is_comparable(|| {})); 9 | -------------------------------------------------------------------------------- /tests/builtin_function_is_empty_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_empty("foo")); 3 | println(is_empty("")); 4 | println(is_empty([1, 2, 3])); 5 | println(is_empty([])); 6 | println(is_empty({a: 1, b: 2, c: 3})); 7 | println(is_empty({})); 8 | -------------------------------------------------------------------------------- /tests/builtin_function_is_instance_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_struct({})); 3 | println(is_struct({ foo: 1, bar: 2 })); 4 | println(is_struct(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_int_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_int(1)); 3 | println(is_int(3.24)); 4 | println(is_int(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_iterable_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_iterable(1 .. 10)); 3 | println(is_iterable([1, 2, 3])); 4 | println(is_iterable(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_iterator_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_iterator(iter(1 .. 10))); 3 | println(is_iterator(iter([1, 2, 3]))); 4 | println(is_iterator(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_nil_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_nil(nil)); 3 | println(is_nil(false)); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_is_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_number(1)); 3 | println(is_number(3.14)); 4 | println(is_number(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_object_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_object(1 .. 10)); 3 | println(is_object("foo")); 4 | println(is_object([1, 2, 3])); 5 | println(is_object(nil)); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_is_range_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_range(1 .. 10)); 3 | println(is_range(nil)); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_is_string_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_string("")); 3 | println(is_string("foo")); 4 | println(is_string(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_struct_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_struct(struct {})); 3 | println(is_struct(struct { foo, bar })); 4 | println(is_struct(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_is_userdata_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { stdin } from io; 3 | println(is_userdata(stdin)); 4 | println(is_userdata(nil)); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_join_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(join(["a", "b", "c"], ",")); 3 | println(join(["a", "b"], ",")); 4 | println(join(["a"], ",")); 5 | println(join([], ",")); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_len_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(len("foo")); 3 | println(len([1, 2, 3])); 4 | println(len({a: 1, b: 2, c: 3})); 5 | -------------------------------------------------------------------------------- /tests/builtin_function_ord_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(ord("f")); 3 | println(ord("foo")); 4 | 5 | -------------------------------------------------------------------------------- /tests/builtin_function_panic_test.hk: -------------------------------------------------------------------------------- 1 | 2 | panic("oops!"); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_print_test.hk: -------------------------------------------------------------------------------- 1 | 2 | print("Hello, "); 3 | println("world!"); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_refcount_test.hk: -------------------------------------------------------------------------------- 1 | println(refcount(nil)); 2 | println(refcount("foo")); 3 | println(refcount([1, 2, 3])); 4 | -------------------------------------------------------------------------------- /tests/builtin_function_sleep_test.hk: -------------------------------------------------------------------------------- 1 | 2 | sleep(10); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_split_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(split("a,b,c", ",")); 3 | println(split("a,b", ",")); 4 | println(split("a", ",")); 5 | println(split("", ",")); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_to_bool_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(to_bool(nil)); 3 | println(to_bool(false)); 4 | println(to_bool(true)); 5 | println(to_bool(0)); 6 | println(to_bool("")); 7 | println(to_bool([])); 8 | -------------------------------------------------------------------------------- /tests/builtin_function_to_int_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(to_int(123)); 3 | println(to_int(1.23)); 4 | println(to_int("123")); 5 | println(to_int("1.23")); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(to_number(123)); 3 | println(to_number(1.23)); 4 | println(to_number("123")); 5 | println(to_number("1.23")); 6 | -------------------------------------------------------------------------------- /tests/builtin_function_to_string_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println([to_string(nil), to_string(false), to_string(true), to_string(1.23), to_string("foo")]); 3 | -------------------------------------------------------------------------------- /tests/builtin_function_type_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(type(nil)); 3 | println(type(false)); 4 | println(type(true)); 5 | println(type(123)); 6 | println(type(1.23)); 7 | println(type("foo")); 8 | println(type([])); 9 | println(type(||{})); 10 | -------------------------------------------------------------------------------- /tests/error_arrays_index_of_invalid_type_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let i = arrays.index_of("foo", 0); 4 | -------------------------------------------------------------------------------- /tests/error_arrays_new_array_invalid_range_capacity_must_be_between_and_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let arr = arrays.new_array(-1); 4 | -------------------------------------------------------------------------------- /tests/error_arrays_new_array_invalid_type_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let arr = arrays.new_array("foo"); 4 | -------------------------------------------------------------------------------- /tests/error_assert_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | assert(true, 1); 3 | -------------------------------------------------------------------------------- /tests/error_cannot_call_value_of_type_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = 1; 3 | a(); 4 | -------------------------------------------------------------------------------- /tests/error_cannot_create_range_from_non_numbers_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = "1" .. 10; 3 | -------------------------------------------------------------------------------- /tests/error_compare_cannot_compare_and_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = compare(1, "foo"); 3 | -------------------------------------------------------------------------------- /tests/error_exit_expected_number_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | exit("foo"); 3 | -------------------------------------------------------------------------------- /tests/error_expects_argument_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let n = len(); 3 | -------------------------------------------------------------------------------- /tests/error_int_cannot_convert_empty_string_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_int(""); 3 | -------------------------------------------------------------------------------- /tests/error_int_cannot_convert_string_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_int("123 x"); 3 | -------------------------------------------------------------------------------- /tests/error_int_cannot_convert_to_integer_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_int(nil); 3 | -------------------------------------------------------------------------------- /tests/error_int_number_literal_is_too_large_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_int("4.9e-324"); 3 | -------------------------------------------------------------------------------- /tests/error_is_empty_has_no_length_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(is_empty(1)); 3 | -------------------------------------------------------------------------------- /tests/error_len_has_no_length_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(len(1)); 3 | -------------------------------------------------------------------------------- /tests/error_math_abs_expected_number_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.abs("foo"); 4 | -------------------------------------------------------------------------------- /tests/error_math_ceil_expected_number_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.ceil("foo"); 4 | -------------------------------------------------------------------------------- /tests/error_math_floor_expected_number_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.floor("foo"); 4 | -------------------------------------------------------------------------------- /tests/error_math_pow_expected_number_but_got_1_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.pow("foo", 1); 4 | -------------------------------------------------------------------------------- /tests/error_math_pow_expected_number_but_got_2_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.pow(1, "foo"); 4 | -------------------------------------------------------------------------------- /tests/error_math_sqrt_expected_number_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | let a = math.sqrt("foo"); 4 | -------------------------------------------------------------------------------- /tests/error_num_cannot_convert_empty_string_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_number(""); 3 | -------------------------------------------------------------------------------- /tests/error_num_cannot_convert_string_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_number("123 x"); 3 | -------------------------------------------------------------------------------- /tests/error_num_cannot_convert_to_number_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_number(nil); 3 | -------------------------------------------------------------------------------- /tests/error_num_number_literal_is_too_large_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_number("4.9e-324"); 3 | -------------------------------------------------------------------------------- /tests/error_os_getenv_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.getenv(1)); 4 | -------------------------------------------------------------------------------- /tests/error_os_system_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { system } from os; 3 | system(1); 4 | -------------------------------------------------------------------------------- /tests/error_panic_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | panic(1); 3 | -------------------------------------------------------------------------------- /tests/error_stack_overflow_test.hk: -------------------------------------------------------------------------------- 1 | 2 | fn f() { 3 | f(); 4 | } 5 | 6 | f(); 7 | -------------------------------------------------------------------------------- /tests/error_str_cannot_convert_to_string_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = to_string([]); 3 | -------------------------------------------------------------------------------- /tests/error_strings_hash_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { hash } from strings; 3 | let a = hash(1); 4 | -------------------------------------------------------------------------------- /tests/error_strings_lower_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { lower } from strings; 3 | let a = lower(1); 4 | -------------------------------------------------------------------------------- /tests/error_strings_trim_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { trim } from strings; 3 | let a = trim(1); 4 | -------------------------------------------------------------------------------- /tests/error_strings_upper_expected_string_but_got_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { upper } from strings; 3 | let a = upper(1); 4 | -------------------------------------------------------------------------------- /tests/error_value_of_type_has_no_capacity_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(cap(1)); 3 | -------------------------------------------------------------------------------- /tests/foreach_test.hk: -------------------------------------------------------------------------------- 1 | 2 | foreach (x in 1 .. 10) { 3 | println(x); 4 | } 5 | 6 | foreach (x in ["foo", "bar", "baz"]) { 7 | println(x); 8 | } 9 | 10 | foreach (x in []) { 11 | println(x); 12 | } 13 | -------------------------------------------------------------------------------- /tests/function_call_test.hk: -------------------------------------------------------------------------------- 1 | 2 | fn f() => nil; 3 | 4 | fn g(a) => nil; 5 | 6 | fn h(a, b) => nil; 7 | 8 | f(); 9 | f(1); 10 | f(1, 2); 11 | 12 | g(); 13 | g(1); 14 | g(1, 2); 15 | 16 | h(); 17 | h(1); 18 | h(1, 2); 19 | -------------------------------------------------------------------------------- /tests/function_declaration_test.hk: -------------------------------------------------------------------------------- 1 | 2 | fn f(a, b) { 3 | return a + b; 4 | } 5 | 6 | let g = |a, b| { 7 | return a - b; 8 | }; 9 | 10 | fn h(a, b) => a + b; 11 | 12 | let i = |a, b| => a - b; 13 | 14 | let j = || { 15 | return 1; 16 | }; 17 | 18 | let k = || => 1; 19 | 20 | fn l() { 21 | fn m() {} 22 | fn n() {} 23 | fn o() {} 24 | fn p() {} 25 | fn q() {} 26 | fn r() {} 27 | fn s() {} 28 | fn t() {} 29 | fn u() {} 30 | } 31 | 32 | println(f(1, 2)); 33 | println(g(3, 2)); 34 | println(h(1, 2)); 35 | println(i(3, 2)); 36 | println(j()); 37 | println(k()); 38 | -------------------------------------------------------------------------------- /tests/if_statement_var_declaration_test.hk: -------------------------------------------------------------------------------- 1 | 2 | fn foo() { 3 | return ["ok", nil]; 4 | } 5 | 6 | fn bar() { 7 | return [nil, "error"]; 8 | } 9 | 10 | fn baz() { 11 | return { ok: "ok", err: nil }; 12 | } 13 | 14 | if (let [ok, err] = foo(); err) { 15 | println(err); 16 | } else { 17 | println(ok); 18 | } 19 | 20 | if (let [ok, err] = bar(); err) { 21 | println(err); 22 | } else { 23 | println(ok); 24 | } 25 | 26 | if (var { ok, err } = baz(); err) { 27 | println(err); 28 | } else { 29 | println(ok); 30 | } 31 | -------------------------------------------------------------------------------- /tests/if_with_var_declaration_test.hk: -------------------------------------------------------------------------------- 1 | 2 | fn foo() { 3 | return ["ok", nil]; 4 | } 5 | 6 | fn bar() { 7 | return [nil, "error"]; 8 | } 9 | 10 | fn baz() { 11 | return { ok: "ok", err: nil }; 12 | } 13 | 14 | if (let [ok, err] = foo(); err) { 15 | println(err); 16 | } else { 17 | println(ok); 18 | } 19 | 20 | if (let [ok, err] = bar(); err) { 21 | println(err); 22 | } else { 23 | println(ok); 24 | } 25 | 26 | if (var { ok, err } = baz(); err) { 27 | println(err); 28 | } else { 29 | println(ok); 30 | } 31 | -------------------------------------------------------------------------------- /tests/import_statement_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.clock()); 4 | 5 | import "numbers" as n; 6 | println(n.PI); 7 | 8 | import { clock } from "os"; 9 | println(clock()); 10 | 11 | import "../examples/module.hk" as m; 12 | println(m.foo()); 13 | 14 | import { bar } from "../examples/module"; 15 | println(bar()); 16 | -------------------------------------------------------------------------------- /tests/iterator_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var it1; 3 | var it2; 4 | 5 | let range = 1 .. 3; 6 | it1 = iter(range); 7 | it2 = it1; 8 | 9 | it1 = next(it1); 10 | 11 | println(it1); 12 | println(it2); 13 | 14 | for (; valid(it1); it1 = next(it1)) { 15 | println(current(it1)); 16 | } 17 | 18 | for (; valid(it2); it2 = next(it2)) { 19 | println(current(it2)); 20 | } 21 | 22 | let arr = ["foo", "bar", "baz"]; 23 | it1 = iter(arr); 24 | it2 = it1; 25 | 26 | it1 = next(it1); 27 | 28 | println(it1); 29 | println(it2); 30 | 31 | for (; valid(it1); it1 = next(it1)) { 32 | println(current(it1)); 33 | } 34 | 35 | for (; valid(it2); it2 = next(it2)) { 36 | println(current(it2)); 37 | } 38 | -------------------------------------------------------------------------------- /tests/looping_statements_test.hk: -------------------------------------------------------------------------------- 1 | 2 | var i; 3 | 4 | i = 0; 5 | loop { 6 | println("foo"); 7 | if (i == 1) 8 | break; 9 | i++; 10 | } 11 | 12 | i = 0; 13 | while (true) { 14 | println("foo"); 15 | if (i == 1) 16 | break; 17 | i++; 18 | } 19 | 20 | while (false) { 21 | println("foo"); 22 | } 23 | 24 | i = 0; 25 | do { 26 | println("foo"); 27 | if (i == 1) 28 | break; 29 | i++; 30 | } while (true); 31 | 32 | do { 33 | println("foo"); 34 | } while (false); 35 | 36 | while! (true) { 37 | println("foo"); 38 | } 39 | 40 | i = 0; 41 | while! (false) { 42 | println("foo"); 43 | if (i == 1) 44 | break; 45 | i++; 46 | } 47 | 48 | do { 49 | println("foo"); 50 | } while! (true); 51 | 52 | i = 0; 53 | do { 54 | if (i == 1) 55 | break; 56 | i++; 57 | } while! (false); 58 | -------------------------------------------------------------------------------- /tests/main_function_args_test.hk: -------------------------------------------------------------------------------- 1 | 2 | for (var i = 0; i < len(args); i++) 3 | println(args[i]); 4 | -------------------------------------------------------------------------------- /tests/match_statement_expression_test.hk: -------------------------------------------------------------------------------- 1 | 2 | match ("foo") { 3 | "foo" => println("foo"); 4 | } 5 | match ("foo") { 6 | "bar" => println("bar"); 7 | } 8 | match ("bar") { 9 | "foo" => println("foo"); 10 | "bar" => println("bar"); 11 | } 12 | match ("bar") { 13 | "foo" => println("foo"); 14 | _ => println("_"); 15 | } 16 | match ("bar") { 17 | "foo" => println("foo"); 18 | "bar" => println("bar"); 19 | _ => println("_"); 20 | } 21 | println(match ("foo") { "foo" => 1, _ => nil }); 22 | println(match ("bar") { "foo" => 1, _ => nil }); 23 | println(match ("bar") { "foo" => 1, "bar" => 2, _ => nil }); 24 | println(match ("baz") { "foo" => 1, "bar" => 2, _ => nil }); 25 | -------------------------------------------------------------------------------- /tests/match_statement_var_declaration_test.hk: -------------------------------------------------------------------------------- 1 | 2 | struct Log { 3 | lvl, 4 | msg 5 | } 6 | 7 | fn info(msg) { 8 | return Log { "info", msg }; 9 | } 10 | 11 | fn warn(msg) { 12 | return Log { "warn", msg }; 13 | } 14 | 15 | fn error(msg) { 16 | return Log { "error", msg }; 17 | } 18 | 19 | match (let { lvl, msg } = info("info message"); lvl) { 20 | "info" => println(msg); 21 | "warn" => println(msg); 22 | "error" => println(msg); 23 | _ => println("unknown log level"); 24 | } 25 | 26 | match (let { lvl, msg } = warn("warn message"); lvl) { 27 | "info" => println(msg); 28 | "warn" => println(msg); 29 | "error" => println(msg); 30 | _ => println("unknown log level"); 31 | } 32 | 33 | match (let { lvl, msg } = error("error message"); lvl) { 34 | "info" => println(msg); 35 | "warn" => println(msg); 36 | "error" => println(msg); 37 | _ => println("unknown log level"); 38 | } 39 | -------------------------------------------------------------------------------- /tests/module_arrays_avg_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | println(arrays.avg([])); 4 | println(arrays.avg([1])); 5 | println(arrays.avg([2, 5, 10])); 6 | -------------------------------------------------------------------------------- /tests/module_arrays_fill_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let arr = arrays.fill("foo", 3); 4 | println(arr); 5 | -------------------------------------------------------------------------------- /tests/module_arrays_index_of_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let arr = ["foo", "bar", "baz"]; 4 | println(arrays.index_of(arr, "baz")); 5 | println(arrays.index_of(arr, "qux")); 6 | -------------------------------------------------------------------------------- /tests/module_arrays_max_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | println(arrays.max([])); 4 | println(arrays.max([1])); 5 | println(arrays.max([10, 5, -5])); 6 | println(arrays.max(["foo", "bar"])); 7 | -------------------------------------------------------------------------------- /tests/module_arrays_min_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | println(arrays.min([])); 4 | println(arrays.min([1])); 5 | println(arrays.min([10, 5, -5])); 6 | println(arrays.min(["foo", "bar"])); 7 | -------------------------------------------------------------------------------- /tests/module_arrays_new_array_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | let arr = arrays.new_array(100); 4 | println(arr); 5 | -------------------------------------------------------------------------------- /tests/module_arrays_reverse_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { reverse } from arrays; 3 | 4 | assert(reverse([]) == [], "reverse([]) == []"); 5 | assert(reverse(["foo"]) == ["foo"], "reverse(['foo']) == ['foo']"); 6 | assert(reverse(["foo", "bar"]) == ["bar", "foo"], "reverse(['foo', 'bar']) == ['bar', 'foo']"); 7 | assert(reverse(["foo", "bar", "baz"]) == ["baz", "bar", "foo"], "reverse(['foo', 'bar', 'baz']) == ['baz', 'bar', 'foo']"); 8 | -------------------------------------------------------------------------------- /tests/module_arrays_sort_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { sort } from arrays; 3 | 4 | assert(sort([]) == [], "sort([]) == []"); 5 | assert(sort([3]) == [3], "sort([3]) == [3]"); 6 | assert(sort([3, 1]) == [1, 3], "sort([3, 1]) == [1, 3]"); 7 | assert(sort([3, 1, 2]) == [1, 2, 3], "sort([3, 1, 2]) == [1, 2, 3]"); 8 | -------------------------------------------------------------------------------- /tests/module_arrays_sum_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import arrays; 3 | println(arrays.sum([])); 4 | println(arrays.sum([1])); 5 | println(arrays.sum([10, 5, -5])); 6 | -------------------------------------------------------------------------------- /tests/module_encoding_ascii85_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import encoding; 3 | let encoded = encoding.ascii85_encode("foo bar baz"); 4 | assert(encoded == 'AoDT1@UX:"@UXQ', 'encoded must be AoDT1@UX:"@UXQ'); 5 | let decoded = encoding.ascii85_decode(encoded); 6 | assert(decoded == "foo bar baz", "decoded must be 'foo bar baz'"); 7 | -------------------------------------------------------------------------------- /tests/module_encoding_base32_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import encoding; 3 | let encoded = encoding.base32_encode("foo bar baz"); 4 | assert(encoded == "MZXW6IDCMFZCAYTBPI======", "encoded must be 'MZXW6IDCMFZCAYTBPI======'"); 5 | let decoded = encoding.base32_decode(encoded); 6 | assert(decoded == "foo bar baz", "decoded must be 'foo bar baz'"); 7 | -------------------------------------------------------------------------------- /tests/module_encoding_base58_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import encoding; 3 | let encoded = encoding.base58_encode("foo bar baz"); 4 | assert(encoded == "SQHFQMRT97NTco3", "encoded must be 'SQHFQMRT97NTco3'"); 5 | let decoded = encoding.base58_decode(encoded); 6 | assert(decoded == "foo bar baz", "decoded must be 'foo bar baz'"); 7 | -------------------------------------------------------------------------------- /tests/module_encoding_base64_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import encoding; 3 | let encoded = encoding.base64_encode("foo bar baz"); 4 | assert(encoded == "Zm9vIGJhciBiYXo=", "encoded must be 'Zm9vIGJhciBiYXo='"); 5 | let decoded = encoding.base64_decode(encoded); 6 | assert(decoded == "foo bar baz", "decoded must be 'foo bar baz'"); 7 | -------------------------------------------------------------------------------- /tests/module_hashing_crc32_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let x = hashing.crc32("foo"); 4 | println(x); 5 | assert(x == 2356372769, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_crc64_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let x = hashing.crc64("foo"); 4 | println(x); 5 | assert(x == 12626267673720558670, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_md5_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "acbd18db4cc2f85cedef654fccc4a4d8"; 4 | let x = hex(hashing.md5("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_ripemd160_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "42cfa211018ea492fdee45ac637b7972a0ad6873"; 4 | let x = hex(hashing.ripemd160("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha1_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"; 4 | let x = hex(hashing.sha1("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha224_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db"; 4 | let x = hex(hashing.sha224("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha256_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"; 4 | let x = hex(hashing.sha256("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha384_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb"; 4 | let x = hex(hashing.sha384("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha3_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01"; 4 | let x = hex(hashing.sha3("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_hashing_sha512_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import hashing; 3 | let expected = "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"; 4 | let x = hex(hashing.sha512("foo")); 5 | assert(x == expected, "x must equal expected"); 6 | -------------------------------------------------------------------------------- /tests/module_ini_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import ini; 3 | let config = ini.load("tests/module_ini_test.ini"); 4 | println(ini.get(config, "general", "name")); 5 | println(ini.get(config, "general", "version")); 6 | println(ini.get(config, "general", "description")); 7 | println(ini.get(config, "general", "author")); 8 | println(ini.get(config, "general", "license")); 9 | println(ini.get(config, "deps", "hook")); 10 | -------------------------------------------------------------------------------- /tests/module_ini_test.ini: -------------------------------------------------------------------------------- 1 | ; 2 | ; manifest.ini 3 | ; 4 | 5 | [general] 6 | name = "cowsay" 7 | version = 0.1.0 8 | description = "Hook's Cowsay" 9 | author = "Fábio de Souza Villaça Medeiros" 10 | license = MIT 11 | 12 | [deps] 13 | hook = "0.1.0" 14 | -------------------------------------------------------------------------------- /tests/module_json_decode_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import json; 3 | println(json.decode("1")); 4 | println(json.decode('"hello"')); 5 | println(json.decode("true")); 6 | println(json.decode("false")); 7 | println(json.decode("null")); 8 | println(json.decode("[1, 2, 3]")); 9 | println(json.decode('{"a": 1, "b": 2, "c": 3}')); 10 | -------------------------------------------------------------------------------- /tests/module_json_encode_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import json; 3 | println(json.encode(1)); 4 | println(json.encode("hello")); 5 | println(json.encode(true)); 6 | println(json.encode(false)); 7 | println(json.encode(nil)); 8 | println(json.encode([1, 2, 3])); 9 | println(json.encode({a: 1, b: 2, c: 3})); 10 | -------------------------------------------------------------------------------- /tests/module_lists_is_empty_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | let list = lists.new_linked_list(); 4 | println(lists.is_empty(list)); 5 | -------------------------------------------------------------------------------- /tests/module_lists_len_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | let list = lists.new_linked_list(); 4 | println(lists.len(list)); 5 | -------------------------------------------------------------------------------- /tests/module_lists_pop_back_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | var list = lists.new_linked_list(); 4 | list = lists.push_back(list, 1); 5 | list = lists.push_back(list, 2); 6 | list = lists.push_back(list, 3); 7 | list = lists.pop_back(list); 8 | println(lists.back(list)); 9 | -------------------------------------------------------------------------------- /tests/module_lists_pop_front_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | var list = lists.new_linked_list(); 4 | list = lists.push_back(list, 1); 5 | list = lists.push_back(list, 2); 6 | list = lists.push_back(list, 3); 7 | list = lists.pop_front(list); 8 | println(lists.front(list)); 9 | -------------------------------------------------------------------------------- /tests/module_lists_push_back_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | var list = lists.new_linked_list(); 4 | list = lists.push_back(list, 1); 5 | list = lists.push_back(list, 2); 6 | println(lists.back(list)); 7 | -------------------------------------------------------------------------------- /tests/module_lists_push_front_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import lists; 3 | var list = lists.new_linked_list(); 4 | list = lists.push_front(list, 1); 5 | list = lists.push_front(list, 2); 6 | println(lists.front(list)); 7 | -------------------------------------------------------------------------------- /tests/module_math_abs_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.abs(1.23)); 4 | println(math.abs(-1.23)); 5 | -------------------------------------------------------------------------------- /tests/module_math_acos_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.acos(0.1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_asin_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.asin(1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_atan_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.atan(1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_cbrt_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.cbrt(27)); 4 | -------------------------------------------------------------------------------- /tests/module_math_ceil_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.ceil(1.23)); 4 | -------------------------------------------------------------------------------- /tests/module_math_cos_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.cos(1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_exp_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.exp(1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_floor_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.floor(1.23)); 4 | -------------------------------------------------------------------------------- /tests/module_math_log10_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.log10(10)); 4 | -------------------------------------------------------------------------------- /tests/module_math_log2_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.log2(10)); 4 | -------------------------------------------------------------------------------- /tests/module_math_log_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.log(10)); 4 | -------------------------------------------------------------------------------- /tests/module_math_pow_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.pow(2, 3)); 4 | -------------------------------------------------------------------------------- /tests/module_math_round_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.round(1.4)); 4 | println(math.round(1.49)); 5 | println(math.round(1.5)); 6 | println(math.round(1.51)); 7 | -------------------------------------------------------------------------------- /tests/module_math_sin_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.sin(1)); 4 | -------------------------------------------------------------------------------- /tests/module_math_sqrt_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.sqrt(9)); 4 | -------------------------------------------------------------------------------- /tests/module_math_tan_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import math; 3 | println(math.tan(1)); 4 | -------------------------------------------------------------------------------- /tests/module_numbers_constants_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import numbers; 3 | println(numbers.PI); 4 | println(numbers.TAU); 5 | println(numbers.LARGEST); 6 | println(numbers.SMALLEST); 7 | println(numbers.MAX_INTEGER); 8 | println(numbers.MIN_INTEGER); 9 | -------------------------------------------------------------------------------- /tests/module_numbers_srand_rand_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import numbers; 3 | import { time } from os; 4 | numbers.srand(time()); 5 | println(numbers.rand()); 6 | -------------------------------------------------------------------------------- /tests/module_os_clock_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.clock()); 4 | -------------------------------------------------------------------------------- /tests/module_os_clocks_per_sec_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.CLOCKS_PER_SEC); 4 | -------------------------------------------------------------------------------- /tests/module_os_getcwd_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { getcwd } from os; 3 | println(getcwd()); 4 | -------------------------------------------------------------------------------- /tests/module_os_getenv_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.getenv("HOOK_HOME")); 4 | -------------------------------------------------------------------------------- /tests/module_os_name_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.name()); 4 | -------------------------------------------------------------------------------- /tests/module_os_system_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { system } from os; 3 | system("echo foo"); 4 | -------------------------------------------------------------------------------- /tests/module_os_time_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import os; 3 | println(os.time()); 4 | -------------------------------------------------------------------------------- /tests/module_secp256r1_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import secp256r1; 3 | import { sha256 } from hashing; 4 | 5 | let key_pair = secp256r1.new_key_pair(); 6 | assert(type(key_pair) == "array", "key_pair must be an array"); 7 | assert(len(key_pair) == 2, "the length of key_pair must be equal to 2"); 8 | 9 | let [ pub_key, priv_key ] = key_pair; 10 | assert(type(pub_key) == "string", "pub_key must be a string"); 11 | assert(type(priv_key) == "string", "priv_key must be a string"); 12 | assert(len(pub_key) == secp256r1.PUBLIC_KEY_SIZE, "length of pub_key must be equal to 33"); 13 | assert(len(priv_key) == secp256r1.PRIVATE_KEY_SIZE, "the length of priv_key must be equal to 32"); 14 | println(hex(pub_key)); 15 | println(hex(priv_key)); 16 | 17 | let secret = secp256r1.shared_secret(pub_key, priv_key); 18 | assert(type(secret) == "string", "secret must be a string"); 19 | assert(len(secret) == secp256r1.SECRET_SIZE, "the length of secret must be equal to 32"); 20 | println(hex(secret)); 21 | 22 | let hash = sha256("foo bar baz"); 23 | assert(len(hash) == secp256r1.HASH_SIZE, "the length of hash must be equal to 32"); 24 | println(hex(hash)); 25 | 26 | let signature = secp256r1.sign_hash(priv_key, hash); 27 | assert(type(signature) == "string", "signature must be a string"); 28 | assert(len(signature) == secp256r1.SIGNATURE_SIZE, "the length of signature must be equal to 64"); 29 | println(hex(signature)); 30 | 31 | let valid = secp256r1.verify_signature(pub_key, hash, signature); 32 | assert(valid, "the signature is invalid"); 33 | println(valid); 34 | -------------------------------------------------------------------------------- /tests/module_socket_new_close_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import socket; 3 | var sock; 4 | sock = socket.new(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP); 5 | socket.close(sock); 6 | sock = socket.new(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP); 7 | socket.close(sock); 8 | -------------------------------------------------------------------------------- /tests/module_strings_ends_with_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { ends_with } from strings; 3 | 4 | assert(ends_with("", "") == false, "ends_with('', '') == false"); 5 | assert(ends_with("foo", "") == false, "ends_with('foo', '') == false"); 6 | assert(ends_with("", "foo") == false, "ends_with('', 'foo') == false"); 7 | assert(ends_with("foo", "foobar") == false, "ends_with('foo', 'foobar') == false"); 8 | assert(ends_with("foobar", "foo") == false, "ends_with('foobar', 'foo') == false"); 9 | assert(ends_with("foobar", "bar") == true, "ends_with('foobar', 'bar') == true"); 10 | -------------------------------------------------------------------------------- /tests/module_strings_hash_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | println(strings.hash("foo")); 4 | -------------------------------------------------------------------------------- /tests/module_strings_lower_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | println(strings.lower("")); 4 | println(strings.lower("foo")); 5 | println(strings.lower("Bar")); 6 | println(strings.lower("BAZ")); 7 | -------------------------------------------------------------------------------- /tests/module_strings_new_string_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | let str = strings.new_string(100); 4 | println(str); 5 | -------------------------------------------------------------------------------- /tests/module_strings_repeat_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | let str = strings.repeat("foo", 3); 4 | println(str); 5 | -------------------------------------------------------------------------------- /tests/module_strings_reverse_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { reverse } from strings; 3 | 4 | assert(reverse("") == "", "reverse('') == ''"); 5 | assert(reverse("foo") == "oof", "reverse('foo') == 'oof'"); 6 | assert(reverse("foobar") == "raboof", "reverse('foobar') == 'raboof'"); 7 | assert(reverse("foobarbaz") == "zabraboof", "reverse('foobarbaz') == 'zabraboof'"); 8 | -------------------------------------------------------------------------------- /tests/module_strings_starts_with_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import { starts_with } from strings; 3 | 4 | assert(starts_with("", "") == false, "starts_with('', '') == false"); 5 | assert(starts_with("foo", "") == false, "starts_with('foo', '') == false"); 6 | assert(starts_with("", "foo") == false, "starts_with('', 'foo') == false"); 7 | assert(starts_with("foo", "foobar") == false, "starts_with('foo', 'foobar') == false"); 8 | assert(starts_with("foobar", "foo") == true, "starts_with('foobar', 'foo') == true"); 9 | assert(starts_with("foobar", "bar") == false, "starts_with('foobar', 'bar') == false"); 10 | -------------------------------------------------------------------------------- /tests/module_strings_trim_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | println(strings.trim("")); 4 | println(strings.trim(" ")); 5 | println(strings.trim(" foo")); 6 | println(strings.trim("bar ")); 7 | println(strings.trim(" baz ")); 8 | -------------------------------------------------------------------------------- /tests/module_strings_upper_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import strings; 3 | println(strings.upper("")); 4 | println(strings.upper("foo")); 5 | println(strings.upper("Bar")); 6 | println(strings.upper("BAZ")); 7 | -------------------------------------------------------------------------------- /tests/module_utf8_len_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import utf8; 3 | println(utf8.len("")); 4 | println(utf8.len("Hi")); 5 | println(utf8.len("你好")); 6 | println(utf8.len("こんにちは")); 7 | -------------------------------------------------------------------------------- /tests/module_utf8_sub_test.hk: -------------------------------------------------------------------------------- 1 | 2 | import utf8; 3 | let str = "こんにちは"; 4 | println(utf8.sub(str, 0, 1)); 5 | println(utf8.sub(str, 1, 2)); 6 | println(utf8.sub(str, 0, 5)); 7 | -------------------------------------------------------------------------------- /tests/nonlocals_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = 1; 3 | fn f (x) { 4 | let b = 2; 5 | fn g (y) { 6 | let c = 3; 7 | let h = |z| { 8 | return z + c + y + b * x * x; 9 | }; 10 | return h; 11 | } 12 | let h = g(a); 13 | return h; 14 | } 15 | let h = f(4); 16 | let r = h(5); 17 | println(r); 18 | -------------------------------------------------------------------------------- /tests/print_scalar_values_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(nil); 3 | println(false); 4 | println(true); 5 | println(123); 6 | println(4.56); 7 | println(0.123); 8 | println(1.23e10); 9 | println(1.23E10); 10 | println(123e+10); 11 | println(123.0e-2); 12 | println(""); 13 | println("foo"); 14 | println(" foo bar baz "); 15 | -------------------------------------------------------------------------------- /tests/range_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println(1 .. 10); 3 | let range = 1 .. 10; 4 | println(range); 5 | -------------------------------------------------------------------------------- /tests/string_concatenation_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println("" + "foo" + "" + "bar" + "baz"); 3 | -------------------------------------------------------------------------------- /tests/string_slice_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let str = "bar"; 3 | 4 | assert(str[0] == "b", "index 0"); 5 | assert(str[1] == "a", "index 1"); 6 | assert(str[2] == "r", "index 2"); 7 | 8 | assert(str[0 .. 0] == "b", "range 0 .. 0"); 9 | assert(str[1 .. 1] == "a", "range 1 .. 1"); 10 | assert(str[2 .. 2] == "r", "range 2 .. 2"); 11 | 12 | assert(str[0 .. 1] == "ba", "range 0 .. 1"); 13 | assert(str[0 .. 2] == "bar", "range 0 .. 2"); 14 | assert(str[0 .. 3] == "bar", "range 0 .. 3"); 15 | 16 | assert(str[1 .. 0] == "", "range 1 .. 0"); 17 | assert(str[2 .. 0] == "", "range 2 .. 0"); 18 | assert(str[3 .. 0] == "", "range 3 .. 0"); 19 | 20 | assert(str[-1 .. 3] == "bar", "range -1 .. 3"); 21 | assert(str[3 .. -1] == "", "range 3 .. -1"); 22 | assert(str[-2 .. -1] == "", "range -2 .. -1"); 23 | assert(str[3 .. 4] == "", "range 3 .. 4"); 24 | -------------------------------------------------------------------------------- /tests/struct_declaration_and_initialization_test.hk: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | a, b 4 | } 5 | println(Foo{1, 2}); 6 | 7 | let Bar = struct { 8 | c, d 9 | }; 10 | println(Bar{3, 4}); 11 | 12 | let Baz = struct { 13 | "e", "f" 14 | }; 15 | println(Baz{5, 6}); 16 | 17 | let Qux = struct { 18 | "g", "h" 19 | }; 20 | println(Qux{7, 8}); 21 | -------------------------------------------------------------------------------- /tests/struct_instance_get_field_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let s1 = {foo: 1, bar: 2, baz: 3}; 3 | println(s1.foo); 4 | println(s1.bar); 5 | println(s1.baz); 6 | 7 | let s2 = {foo: {bar: 1, baz: 2}}; 8 | println(s2.foo.baz); 9 | 10 | let s3 = {"foo": 1}; 11 | println(s3.foo); 12 | -------------------------------------------------------------------------------- /tests/struct_instance_test.hk: -------------------------------------------------------------------------------- 1 | 2 | println({}); 3 | println({a: 1}); 4 | println({a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10}); 5 | println({"a": 1, "b": 2}); 6 | -------------------------------------------------------------------------------- /tests/variable_declaration_test.hk: -------------------------------------------------------------------------------- 1 | 2 | let a = 1; 3 | let [b, c] = [2, 3]; 4 | var d; 5 | var e = 4; 6 | let [f, g] = ["foo", "bar"]; 7 | var [h] = ["baz"]; 8 | var [i, j] = ["qux", "quux"]; 9 | 10 | let {k, l} = {k: "foo", l: "bar"}; 11 | var {m} = {m: "baz"}; 12 | var {n, o, p} = {n: "qux", p: "quux"}; 13 | 14 | let [_, q, _] = [1, 2, 3]; 15 | var [r, _, s] = [4, 5, 6]; 16 | 17 | println(a); 18 | println(b); 19 | println(c); 20 | println(d); 21 | println(e); 22 | println(f); 23 | println(g); 24 | println(h); 25 | println(i); 26 | println(j); 27 | println(k); 28 | println(l); 29 | println(m); 30 | println(n); 31 | println(o); 32 | println(p); 33 | println(q); 34 | println(r); 35 | println(s); 36 | --------------------------------------------------------------------------------