├── .clang-format ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── hash_table_benchmark.cpp └── main.cpp ├── cmake ├── coverage.cmake └── update_submodules.cmake ├── config.h.in ├── coverage.sh ├── examples ├── assignment │ ├── associativity.lox │ ├── global.lox │ ├── grouping.lox │ ├── infix_operator.lox │ ├── local.lox │ ├── prefix_operator.lox │ ├── syntax.lox │ ├── to_this.lox │ └── undefined.lox ├── benchmark │ ├── binary_trees.lox │ ├── equality.lox │ ├── fib.lox │ ├── instantiation.lox │ ├── invocation.lox │ ├── method_call.lox │ ├── properties.lox │ ├── string_equality.lox │ ├── sum.lox │ ├── trees.lox │ └── zoo.lox ├── block │ ├── empty.lox │ └── scope.lox ├── bool │ ├── equality.lox │ └── not.lox ├── call │ ├── bool.lox │ ├── nil.lox │ ├── num.lox │ ├── object.lox │ └── string.lox ├── class │ ├── empty.lox │ ├── inherit_self.lox │ ├── inherited_method.lox │ ├── local_inherit_other.lox │ ├── local_inherit_self.lox │ ├── local_reference_self.lox │ └── reference_self.lox ├── closure │ ├── assign_to_closure.lox │ ├── assign_to_shadowed_later.lox │ ├── close_over_function_parameter.lox │ ├── close_over_later_variable.lox │ ├── close_over_method_parameter.lox │ ├── closed_closure_in_function.lox │ ├── nested_closure.lox │ ├── open_closure_in_function.lox │ ├── reference_closure_multiple_times.lox │ ├── reuse_closure_slot.lox │ ├── shadow_closure_with_local.lox │ ├── unused_closure.lox │ └── unused_later_closure.lox ├── comments │ ├── line_at_eof.lox │ ├── only_line_comment.lox │ ├── only_line_comment_and_line.lox │ └── unicode.lox ├── constructor ├── empty_file.lox ├── expressions │ └── evaluate.lox ├── field │ ├── call_function_field.lox │ ├── call_nonfunction_field.lox │ ├── get_and_set_method.lox │ ├── get_on_bool.lox │ ├── get_on_class.lox │ ├── get_on_function.lox │ ├── get_on_nil.lox │ ├── get_on_num.lox │ ├── get_on_string.lox │ ├── many.lox │ ├── method.lox │ ├── method_binds_this.lox │ ├── on_instance.lox │ ├── set_evaluation_order.lox │ ├── set_on_bool.lox │ ├── set_on_class.lox │ ├── set_on_function.lox │ ├── set_on_nil.lox │ ├── set_on_num.lox │ ├── set_on_string.lox │ └── undefined.lox ├── for │ ├── class_in_body.lox │ ├── closure_in_body.lox │ ├── fun_in_body.lox │ ├── return_closure.lox │ ├── return_inside.lox │ ├── scope.lox │ ├── statement_condition.lox │ ├── statement_increment.lox │ ├── statement_initializer.lox │ ├── syntax.lox │ └── var_in_body.lox ├── function │ ├── body_must_be_block.lox │ ├── empty_body.lox │ ├── extra_arguments.lox │ ├── local_mutual_recursion.lox │ ├── local_recursion.lox │ ├── missing_arguments.lox │ ├── missing_comma_in_parameters.lox │ ├── mutual_recursion.lox │ ├── parameters.lox │ ├── print.lox │ ├── recursion.lox │ ├── too_many_arguments.lox │ └── too_many_parameters.lox ├── if │ ├── class_in_else.lox │ ├── class_in_then.lox │ ├── dangling_else.lox │ ├── else.lox │ ├── fun_in_else.lox │ ├── fun_in_then.lox │ ├── if.lox │ ├── truth.lox │ ├── var_in_else.lox │ └── var_in_then.lox ├── inheritance │ ├── constructor.lox │ ├── inherit_from_function.lox │ ├── inherit_from_nil.lox │ ├── inherit_from_number.lox │ ├── inherit_methods.lox │ ├── parenthesized_superclass.lox │ └── set_fields_from_base_class.lox ├── limit │ ├── loop_too_large.lox │ ├── no_reuse_constants.lox │ ├── stack_overflow.lox │ ├── too_many_constants.lox │ ├── too_many_locals.lox │ └── too_many_upvalues.lox ├── logical_operator │ ├── and.lox │ ├── and_truth.lox │ ├── or.lox │ └── or_truth.lox ├── method │ ├── arity.lox │ ├── empty_block.lox │ ├── extra_arguments.lox │ ├── missing_arguments.lox │ ├── not_found.lox │ ├── print_bound_method.lox │ ├── refer_to_name.lox │ ├── too_many_arguments.lox │ └── too_many_parameters.lox ├── nil │ └── literal.lox ├── number │ ├── decimal_point_at_eof.lox │ ├── leading_dot.lox │ ├── literals.lox │ ├── nan_equality.lox │ └── trailing_dot.lox ├── operator │ ├── add.lox │ ├── add_bool_nil.lox │ ├── add_bool_num.lox │ ├── add_bool_string.lox │ ├── add_nil_nil.lox │ ├── add_num_nil.lox │ ├── add_string_nil.lox │ ├── comparison.lox │ ├── divide.lox │ ├── divide_nonnum_num.lox │ ├── divide_num_nonnum.lox │ ├── equals.lox │ ├── equals_class.lox │ ├── equals_method.lox │ ├── greater_nonnum_num.lox │ ├── greater_num_nonnum.lox │ ├── greater_or_equal_nonnum_num.lox │ ├── greater_or_equal_num_nonnum.lox │ ├── less_nonnum_num.lox │ ├── less_num_nonnum.lox │ ├── less_or_equal_nonnum_num.lox │ ├── less_or_equal_num_nonnum.lox │ ├── multiply.lox │ ├── multiply_nonnum_num.lox │ ├── multiply_num_nonnum.lox │ ├── negate.lox │ ├── negate_nonnum.lox │ ├── not.lox │ ├── not_class.lox │ ├── not_equals.lox │ ├── subtract.lox │ ├── subtract_nonnum_num.lox │ └── subtract_num_nonnum.lox ├── precedence.lox ├── print │ └── missing_argument.lox ├── regression │ ├── 394.lox │ └── 40.lox ├── return │ ├── after_else.lox │ ├── after_if.lox │ ├── after_while.lox │ ├── at_top_level.lox │ ├── in_function.lox │ ├── in_method.lox │ └── return_nil_if_no_value.lox ├── scanning │ ├── identifiers.lox │ ├── keywords.lox │ ├── numbers.lox │ ├── punctuators.lox │ ├── strings.lox │ └── whitespace.lox ├── string │ ├── error_after_multiline.lox │ ├── literals.lox │ ├── multiline.lox │ └── unterminated.lox ├── super │ ├── bound_method.lox │ ├── call_other_method.lox │ ├── call_same_method.lox │ ├── closure.lox │ ├── constructor.lox │ ├── extra_arguments.lox │ ├── indirectly_inherited.lox │ ├── missing_arguments.lox │ ├── no_superclass_bind.lox │ ├── no_superclass_call.lox │ ├── no_superclass_method.lox │ ├── parenthesized.lox │ ├── reassign_superclass.lox │ ├── super_at_top_level.lox │ ├── super_in_closure_in_inherited_method.lox │ ├── super_in_inherited_method.lox │ ├── super_in_top_level_function.lox │ ├── super_without_dot.lox │ ├── super_without_name.lox │ └── this_in_superclass_method.lox ├── this │ ├── closure.lox │ ├── nested_class.lox │ ├── nested_closure.lox │ ├── this_at_top_level.lox │ ├── this_in_method.lox │ └── this_in_top_level_function.lox ├── unexpected_character.lox ├── variable │ ├── collide_with_parameter.lox │ ├── duplicate_local.lox │ ├── duplicate_parameter.lox │ ├── early_bound.lox │ ├── in_middle_of_block.lox │ ├── in_nested_block.lox │ ├── local_from_method.lox │ ├── redeclare_global.lox │ ├── redefine_global.lox │ ├── scope_reuse_in_different_blocks.lox │ ├── shadow_and_local.lox │ ├── shadow_global.lox │ ├── shadow_local.lox │ ├── undefined_global.lox │ ├── undefined_local.lox │ ├── uninitialized.lox │ ├── unreached_undefined.lox │ ├── use_false_as_var.lox │ ├── use_global_in_initializer.lox │ ├── use_local_in_initializer.lox │ ├── use_nil_as_var.lox │ └── use_this_as_var.lox └── while │ ├── class_in_body.lox │ ├── closure_in_body.lox │ ├── fun_in_body.lox │ ├── return_closure.lox │ ├── return_inside.lox │ ├── syntax.lox │ └── var_in_body.lox ├── include ├── chunk.h ├── compiler.h ├── contract.h ├── exception.h ├── gc.h ├── hash_table.h ├── heap.h ├── instruction.h ├── list.h ├── native.h ├── object.h ├── scanner.h ├── stack.h ├── type_list.h ├── value.h └── vm.h ├── main.cpp ├── src ├── CMakeLists.txt ├── chunk.cpp ├── compiler.cpp ├── scanner.cpp ├── value.cpp └── vm.cpp ├── tests ├── CMakeLists.txt ├── chunk_tests.cpp ├── compiler_tests.cpp ├── gc_tests.cpp ├── hash_table_tests.cpp ├── heap_tests.cpp ├── helper.h ├── list_tests.cpp ├── lox_tests.cpp ├── native_tests.cpp ├── object_tests.cpp ├── scanner_tests.cpp ├── stack_tests.cpp ├── type_list_tests.cpp └── value_tests.cpp └── tools └── CMakeLists.txt /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: push 4 | 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | max-parallel: 2 10 | matrix: 11 | compiler: [gcc, clang] 12 | steps: 13 | - uses: actions/checkout@master 14 | 15 | - name: Install 16 | run: | 17 | if [ "${{ matrix.compiler }}" = "gcc" ]; then 18 | echo "::set-env name=CC::gcc" 19 | echo "::set-env name=CXX::g++" 20 | else 21 | echo "::set-env name=CC::clang" 22 | echo "::set-env name=CXX::clang++" 23 | fi 24 | sudo apt-get install lcov 25 | 26 | - name: Unit test 27 | run: | 28 | mkdir -p build && cd build 29 | cmake -DCODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug .. 30 | cmake --build . -- -j2 31 | ctest -j8 32 | if [ "${{ matrix.compiler }}" = "gcc" ]; then 33 | lcov --directory . --capture -o coverage.info 34 | lcov --remove coverage.info -o coverage.info \ 35 | '*/tools/*' \ 36 | '*/tests/*' \ 37 | '*/usr/include/*' 38 | bash <(curl -s https://codecov.io/bash) 39 | fi 40 | 41 | - name: Benchmark 42 | run: | 43 | mkdir -p build_benchmark && cd build_benchmark 44 | cmake -DCMAKE_BUILD_TYPE=Release .. 45 | cmake --build . -- -j2 46 | ./benchmark/lox_benchmark 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Poject 35 | .vscode 36 | build* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/benchmark"] 2 | path = tools/benchmark 3 | url = https://github.com/google/benchmark.git 4 | [submodule "submodules/doctest"] 5 | path = tools/doctest 6 | url = https://github.com/onqtam/doctest.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project( 4 | Lox-modern-cpp 5 | VERSION 0.1 6 | DESCRIPTION "Lox modern cpp implement" 7 | LANGUAGES CXX) 8 | 9 | set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) 10 | include(coverage) 11 | include(update_submodules) 12 | 13 | enable_testing() 14 | 15 | set(CMAKE_CXX_STANDARD 17) 16 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 17 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 18 | 19 | set(CMAKE_CXX_FLAGS_RELEASE 20 | "${CMAKE_CXX_FLAGS_RELEASE} -DDOCTEST_CONFIG_DISABLE") 21 | 22 | set(BENCHMARK_ENABLE_TESTING 23 | OFF 24 | CACHE BOOL "Suppressing benchmark's tests" FORCE) 25 | 26 | set(BENCHMARK_DIR ${PROJECT_SOURCE_DIR}/tools/benchmark) 27 | set(DOCTEST_DIR ${PROJECT_SOURCE_DIR}/tools/doctest) 28 | add_subdirectory(tools) 29 | 30 | configure_file(config.h.in ${CMAKE_BINARY_DIR}/config.h @ONLY) 31 | 32 | add_subdirectory(benchmark) 33 | add_subdirectory(src) 34 | add_subdirectory(tests) 35 | 36 | add_executable(lox main.cpp ${TESTS_SOURCES}) 37 | add_dependencies(lox doctest) 38 | target_link_libraries(lox PUBLIC lox_core) 39 | 40 | include(${DOCTEST_DIR}/scripts/cmake/doctest.cmake) 41 | doctest_discover_tests(lox) 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 codingpotato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lox Modern Cpp 2 | 3 | ![build](https://github.com/codingpotato/Lox-modern-cpp/workflows/build/badge.svg) 4 | [![codecov](https://codecov.io/gh/codingpotato/Lox-modern-cpp/branch/master/graph/badge.svg)](https://codecov.io/gh/codingpotato/Lox-modern-cpp) 5 | 6 | Lox Modern Cpp is a modern cpp (C++17) implement of Lox programming language described in Bob Nystrom's book: [Crafting Interpreters](http://craftinginterpreters.com). The bytecode virtual machine is implemented by new modern cpp features to make it fast, cache friendly, lightweight and modular. 7 | 8 | ## Lox language 9 | Lox is a programming language described in Bob Nystrom's book: [Crafting Interpreters](http://craftinginterpreters.com). The syntax is similiar to C, with dynamic types and garbage collector. Folowing is a example to calcute the sum of 10000000. 10 | 11 | ``` 12 | var sum = 0.0; 13 | var i = 0; 14 | while (i < 10000000) { 15 | sum = sum + i; 16 | i = i + 1; 17 | } 18 | print sum; 19 | ``` 20 | 21 | For more details on Lox's syntax, check out the [description](http://craftinginterpreters.com/the-lox-language.html) 22 | in Bob's book. 23 | 24 | ## Release Build 25 | Dependency: 26 | - C++17 standard compaitible compiler (gcc and clang tested) 27 | - cmake (> 3.13) 28 | 29 | Build steps: 30 | ``` 31 | mkdir build 32 | cd build 33 | cmake -DCMAKE_BUILD_TYPE=Release .. 34 | ``` 35 | 36 | ## Usage 37 | Run an interactive REPL interpreter: 38 | 39 | ``` 40 | ./lox 41 | ``` 42 | 43 | Execute lox source files: 44 | 45 | ``` 46 | ./lox 47 | ``` 48 | 49 | ## Unit tests 50 | Lox Modern Cpp use [doctest](https://github.com/onqtam/doctest) for unit tests. All lox function tests come from [Bob Nystrom's implemenations of Lox](https://github.com/munificent/craftinginterpreters). Use following sciprt to run all unit tests and generate the code coverage result: 51 | 52 | ``` 53 | ./coverage.sh 54 | ``` 55 | 56 | ## Benchmark 57 | Lox Modern Cpp uses google [benchmark](https://github.com/google/benchmark) for benchmarking. Run lox-benchmark after release build to run the benchmarking: 58 | 59 | ``` 60 | ./benchmark/lox-benchmark 61 | ``` 62 | 63 | Test on Mac OS X, compiled with Apple clang 11.0.3: 64 | 65 | ``` 66 | (8 X 3600 MHz CPU s) 67 | CPU Caches: 68 | L1 Data 32 KiB (x4) 69 | L1 Instruction 32 KiB (x4) 70 | L2 Unified 256 KiB (x4) 71 | L3 Unified 8192 KiB (x1) 72 | ``` 73 | #### Result of Lox Modern Cpp (Unit: second) 74 | 75 | | **Benchmark** | **Min.** | **Max.** | **Average** | 76 | | ------------- | -------: | -------: | ----------: | 77 | | sum.lox | 0.33 | 0.35 | 0.34 | 78 | | fib.lox | 1.02 | 1.03 | 1.02 | 79 | | equality.lox | 1.48 | 1.49 | 1.48 | 80 | 81 | #### Result of Clox, Bob Nystrom's C implementation (Unit: second) 82 | 83 | | **Benchmark** | **Min.** | **Max.** | **Average** | 84 | | ------------- | -------: | -------: | ----------: | 85 | | sum.lox | 0.38 | 0.38 | 0.38 | 86 | | fib.lox | 0.91 | 0.91 | 0.91 | 87 | | equality.lox | 1.45 | 1.46 | 1.46 | 88 | 89 | ## Todo 90 | - [ ] Classes and Instances 91 | - [ ] Methods and Initializers 92 | - [ ] Superclasses 93 | 94 | ## Contributing 95 | If you find any error or have a suggestion, please do file an issue or send a pull request. Thank you! 96 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES hash_table_benchmark.cpp main.cpp) 2 | 3 | add_executable(lox_benchmark ${SOURCES}) 4 | target_include_directories(lox_benchmark PRIVATE ${PROJECT_SOURCE_DIR}/include 5 | ${CMAKE_BINARY_DIR}) 6 | target_link_libraries(lox_benchmark PRIVATE lox_core benchmark) 7 | -------------------------------------------------------------------------------- /benchmark/hash_table_benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "hash_table.h" 6 | #include "object.h" 7 | 8 | static void hash_table(benchmark::State& state) { 9 | while (state.KeepRunning()) { 10 | lox::Hash_table table; 11 | std::vector> strings; 12 | for (auto i = 0; i < 100; ++i) { 13 | strings.emplace_back( 14 | std::make_unique("test string " + std::to_string(i))); 15 | } 16 | for (std::size_t i = 0; i < strings.size(); ++i) { 17 | table.insert(strings[i].get(), lox::Value{static_cast(i)}); 18 | } 19 | double result = 0; 20 | for (std::size_t i = 0; i < strings.size(); ++i) { 21 | if (auto value = table.get_if(strings[i].get()); value != nullptr) { 22 | benchmark::DoNotOptimize(result += value->as_double()); 23 | } 24 | } 25 | } 26 | } 27 | BENCHMARK(hash_table); 28 | -------------------------------------------------------------------------------- /benchmark/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "config.h" 8 | #include "vm.h" 9 | 10 | BENCHMARK_MAIN(); 11 | 12 | static std::string load_source(std::string file_path) noexcept { 13 | std::ifstream ifs(std::move(file_path)); 14 | return std::string{std::istreambuf_iterator{ifs}, 15 | std::istreambuf_iterator{}}; 16 | } 17 | 18 | static void run(std::string source) noexcept { 19 | std::ostringstream oss; 20 | lox::VM{oss}.interpret(std::move(source)); 21 | } 22 | 23 | #define LOX_BENCHMARK(name) \ 24 | static void name(benchmark::State& state) { \ 25 | auto source = load_source(EXAMPLES_DIR "/benchmark/" #name ".lox"); \ 26 | while (state.KeepRunning()) { \ 27 | run(source); \ 28 | } \ 29 | } \ 30 | BENCHMARK(name); 31 | 32 | LOX_BENCHMARK(equality) 33 | LOX_BENCHMARK(fib) 34 | LOX_BENCHMARK(sum) 35 | -------------------------------------------------------------------------------- /cmake/coverage.cmake: -------------------------------------------------------------------------------- 1 | add_library(coverage_config INTERFACE) 2 | option(CODE_COVERAGE "Enable coverage reporting" OFF) 3 | if(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 4 | target_compile_options(coverage_config INTERFACE -O0 -g --coverage) 5 | target_link_options(coverage_config INTERFACE --coverage) 6 | endif(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 7 | -------------------------------------------------------------------------------- /cmake/update_submodules.cmake: -------------------------------------------------------------------------------- 1 | find_package(Git QUIET) 2 | if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") 3 | option(GIT_SUBMODULE "Check submodules during build" ON) 4 | if(GIT_SUBMODULE) 5 | message(STATUS "Submodule update") 6 | execute_process( 7 | COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive 8 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 9 | RESULT_VARIABLE GIT_SUBMOD_RESULT) 10 | if(NOT GIT_SUBMOD_RESULT EQUAL "0") 11 | message( 12 | FATAL_ERROR 13 | "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules" 14 | ) 15 | endif() 16 | endif() 17 | endif() 18 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef LOX_CONFIG_H 2 | #define LOX_CONFIG_H 3 | 4 | #define EXAMPLES_DIR "@PROJECT_SOURCE_DIR@/examples" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /coverage.sh: -------------------------------------------------------------------------------- 1 | mkdir -p build && cd build 2 | cmake -DCODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug .. 3 | cmake --build . -- -j8 4 | ctest -j8 5 | 6 | lcov --directory . --capture --output-file coverage.info 7 | lcov --remove coverage.info -o coverage.info \ 8 | '*/tools/*' \ 9 | '*/tests/*' \ 10 | '*/usr/include/*' 11 | genhtml -o coverage coverage.info 12 | -------------------------------------------------------------------------------- /examples/assignment/associativity.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | var b = "b"; 3 | var c = "c"; 4 | 5 | // Assignment is right-associative. 6 | a = b = c; 7 | print a; // expect: c 8 | print b; // expect: c 9 | print c; // expect: c 10 | -------------------------------------------------------------------------------- /examples/assignment/global.lox: -------------------------------------------------------------------------------- 1 | var a = "before"; 2 | print a; // expect: before 3 | 4 | a = "after"; 5 | print a; // expect: after 6 | 7 | print a = "arg"; // expect: arg 8 | print a; // expect: arg 9 | -------------------------------------------------------------------------------- /examples/assignment/grouping.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | (a) = "value"; // expect: [line 2] Error at '=': Invalid assignment target. 3 | -------------------------------------------------------------------------------- /examples/assignment/infix_operator.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | var b = "b"; 3 | a + b = "value"; // expect: [line 3] Error at '=': Invalid assignment target. 4 | -------------------------------------------------------------------------------- /examples/assignment/local.lox: -------------------------------------------------------------------------------- 1 | { 2 | var a = "before"; 3 | print a; // expect: before 4 | 5 | a = "after"; 6 | print a; // expect: after 7 | 8 | print a = "arg"; // expect: arg 9 | print a; // expect: arg 10 | } 11 | -------------------------------------------------------------------------------- /examples/assignment/prefix_operator.lox: -------------------------------------------------------------------------------- 1 | var a = "a"; 2 | !a = "value"; // expect: [line 2] Error at '=': Invalid assignment target. 3 | -------------------------------------------------------------------------------- /examples/assignment/syntax.lox: -------------------------------------------------------------------------------- 1 | // Assignment on RHS of variable. 2 | var a = "before"; 3 | var c = a = "var"; 4 | print a; // expect: var 5 | print c; // expect: var 6 | -------------------------------------------------------------------------------- /examples/assignment/to_this.lox: -------------------------------------------------------------------------------- 1 | class Foo { 2 | Foo() { 3 | this = "value"; // Error at '=': Invalid assignment target. 4 | } 5 | } 6 | 7 | Foo(); 8 | -------------------------------------------------------------------------------- /examples/assignment/undefined.lox: -------------------------------------------------------------------------------- 1 | unknown = "what"; 2 | // expect: Undefined variable 'unknown'. 3 | // expect: [line 0001] in