Repository: crystal-lang/crystal Branch: master Commit: f4c2f0ab510c Files: 2517 Total size: 16.3 MB Directory structure: gitextract_6d0b5p8f/ ├── .ameba.yml ├── .circleci/ │ └── config.yml ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.md │ │ ├── config.yml │ │ ├── discussion.md │ │ └── feature-request.md │ ├── PULL_REQUEST_TEMPLATE/ │ │ └── pull_request_template.md │ ├── actionlint.yaml │ ├── renovate.json │ ├── workflows/ │ │ ├── aarch64.yml │ │ ├── backport.yml │ │ ├── docs.yml │ │ ├── forward-compatibility.yml │ │ ├── interpreter.yml │ │ ├── lint.yml │ │ ├── linux.yml │ │ ├── llvm.yml │ │ ├── macos.yml │ │ ├── mingw-w64-steps.yml │ │ ├── mingw-w64.yml │ │ ├── openssl.yml │ │ ├── regex-engine.yml │ │ ├── smoke.yml │ │ ├── update-devenv.yml │ │ ├── wasm32.yml │ │ ├── win.yml │ │ ├── win_build_portable.yml │ │ └── xml.yml │ └── zizmor.yml ├── .gitignore ├── .mailmap ├── .markdownlint.yaml ├── .markdownlintignore ├── .well-known/ │ └── funding-manifest-urls ├── Brewfile ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSES/ │ ├── Apache-2.0.txt │ ├── MIT.txt │ └── Swift-exception.txt ├── Makefile ├── Makefile.win ├── NOTICE.md ├── README.md ├── REUSE.toml ├── SECURITY.md ├── UPGRADING.md ├── _typos.toml ├── bin/ │ ├── check-compiler-flag │ ├── ci │ ├── crystal │ ├── crystal.bat │ └── crystal.ps1 ├── devenv.nix ├── devenv.yaml ├── doc/ │ ├── changelogs/ │ │ ├── README.md │ │ ├── pre-1.0.md │ │ ├── v1.0.md │ │ ├── v1.1.md │ │ ├── v1.10.md │ │ ├── v1.11.md │ │ ├── v1.12.md │ │ ├── v1.13.md │ │ ├── v1.14.md │ │ ├── v1.15.md │ │ ├── v1.16.md │ │ ├── v1.17.md │ │ ├── v1.18.md │ │ ├── v1.19.md │ │ ├── v1.2.md │ │ ├── v1.3.md │ │ ├── v1.4.md │ │ ├── v1.5.md │ │ ├── v1.6.md │ │ ├── v1.7.md │ │ ├── v1.8.md │ │ └── v1.9.md │ └── man/ │ ├── crystal-build.adoc │ ├── crystal-docs.adoc │ ├── crystal-env.adoc │ ├── crystal-eval.adoc │ ├── crystal-init.adoc │ ├── crystal-play.adoc │ ├── crystal-run.adoc │ ├── crystal-spec.adoc │ ├── crystal-tool-dependencies.adoc │ ├── crystal-tool-format.adoc │ ├── crystal-tool-macro_code_coverage.adoc │ ├── crystal-tool-unreachable.adoc │ └── crystal.adoc ├── etc/ │ ├── completion.bash │ ├── completion.fish │ ├── completion.zsh │ ├── gdb/ │ │ └── crystal_formatters.py │ ├── lldb/ │ │ └── crystal_formatters.py │ ├── msvc/ │ │ └── crystal.natvis │ └── win-ci/ │ ├── build-ffi.ps1 │ ├── build-gc.ps1 │ ├── build-iconv.ps1 │ ├── build-llvm.ps1 │ ├── build-mpir.ps1 │ ├── build-openssl.ps1 │ ├── build-pcre.ps1 │ ├── build-pcre2.ps1 │ ├── build-xml2.ps1 │ ├── build-yaml.ps1 │ ├── build-z.ps1 │ ├── crystal.iss │ ├── cygwin-build-iconv.sh │ └── setup.ps1 ├── lib/ │ └── .shards.info ├── man/ │ └── crystal.1 ├── samples/ │ ├── 2048.cr │ ├── Makefile │ ├── Makefile.win │ ├── binary-trees.cr │ ├── brainfuck.cr │ ├── channel_primes.cr │ ├── channel_select.cr │ ├── compiler/ │ │ ├── formatter_example.cr │ │ ├── transformer_example.cr │ │ └── visitor_example.cr │ ├── conway.cr │ ├── degree_days.cr │ ├── egrep.cr │ ├── fannkuch-redux.cr │ ├── fibonacci.cr │ ├── havlak.cr │ ├── http_server.cr │ ├── impl.cr │ ├── llvm/ │ │ └── brainfuck.cr │ ├── mandelbrot.cr │ ├── mandelbrot2.cr │ ├── matmul.cr │ ├── meteor.cr │ ├── mt_gc_test.cr │ ├── nbodies.cr │ ├── neural_net.cr │ ├── noise.cr │ ├── pig.cr │ ├── pretty_json.cr │ ├── quine.cr │ ├── red_black_tree.cr │ ├── sdl/ │ │ ├── fire.cr │ │ ├── fire.txt │ │ ├── raytracer.cr │ │ ├── sdl/ │ │ │ ├── lib_sdl.cr │ │ │ ├── sdl.cr │ │ │ └── surface.cr │ │ ├── tv.cr │ │ └── tv.txt │ ├── sieve.cr │ ├── spectral-norm.cr │ ├── sudoku.cr │ ├── tcp_client.cr │ ├── tcp_server.cr │ ├── text_raytracer.cr │ ├── tree.cr │ └── wordcount.cr ├── scripts/ │ ├── docs-versions.sh │ ├── generate_data.mk │ ├── generate_glob_specs.sh │ ├── generate_grapheme_break_specs.cr │ ├── generate_grapheme_properties.cr │ ├── generate_html_entities.cr │ ├── generate_llvm_version_info.cr │ ├── generate_object_properties.cr │ ├── generate_ssl_server_defaults.cr │ ├── generate_unicode_data.cr │ ├── generate_windows_zone_names.cr │ ├── git/ │ │ └── pre-commit │ ├── github-changelog.cr │ ├── grapheme_properties.ecr │ ├── html_entities.ecr │ ├── print_regex_config.cr │ ├── release-update.sh │ ├── test_ssl_server.cr │ ├── unicode_data.ecr │ ├── update-changelog.sh │ ├── update-distribution-scripts.sh │ ├── update-shards.sh │ └── windows_zone_names.ecr ├── shard.yml ├── shell.nix ├── spec/ │ ├── all_spec.cr │ ├── compiler/ │ │ ├── codegen/ │ │ │ ├── abi/ │ │ │ │ ├── aarch64_spec.cr │ │ │ │ ├── arm_spec.cr │ │ │ │ ├── avr_spec.cr │ │ │ │ ├── x86_64_spec.cr │ │ │ │ └── x86_spec.cr │ │ │ ├── alias_spec.cr │ │ │ ├── and_spec.cr │ │ │ ├── array_literal_spec.cr │ │ │ ├── asm_spec.cr │ │ │ ├── automatic_cast_spec.cr │ │ │ ├── block_spec.cr │ │ │ ├── c_abi/ │ │ │ │ ├── c_abi_spec.cr │ │ │ │ └── c_abi_x86_64_spec.cr │ │ │ ├── c_enum_spec.cr │ │ │ ├── c_struct_spec.cr │ │ │ ├── c_union_spec.cr │ │ │ ├── case_spec.cr │ │ │ ├── cast_spec.cr │ │ │ ├── class_spec.cr │ │ │ ├── class_var_spec.cr │ │ │ ├── closure_spec.cr │ │ │ ├── const_spec.cr │ │ │ ├── debug_spec.cr │ │ │ ├── def_default_value_spec.cr │ │ │ ├── def_spec.cr │ │ │ ├── double_splat_spec.cr │ │ │ ├── enum_spec.cr │ │ │ ├── exception_spec.cr │ │ │ ├── experimental_spec.cr │ │ │ ├── extern_spec.cr │ │ │ ├── fun_spec.cr │ │ │ ├── generic_class_spec.cr │ │ │ ├── hash_literal_spec.cr │ │ │ ├── hooks_spec.cr │ │ │ ├── if_spec.cr │ │ │ ├── is_a_spec.cr │ │ │ ├── lib_spec.cr │ │ │ ├── macro_spec.cr │ │ │ ├── magic_constants_spec.cr │ │ │ ├── method_missing_spec.cr │ │ │ ├── module_spec.cr │ │ │ ├── multi_assign_spec.cr │ │ │ ├── named_args_spec.cr │ │ │ ├── named_tuple_spec.cr │ │ │ ├── new_spec.cr │ │ │ ├── next_spec.cr │ │ │ ├── nilable_cast_spec.cr │ │ │ ├── no_return_spec.cr │ │ │ ├── not_spec.cr │ │ │ ├── offsetof_spec.cr │ │ │ ├── op_assign_spec.cr │ │ │ ├── or_spec.cr │ │ │ ├── pointer_spec.cr │ │ │ ├── previous_def_spec.cr │ │ │ ├── primitives_spec.cr │ │ │ ├── private_spec.cr │ │ │ ├── proc_spec.cr │ │ │ ├── regex_literal_spec.cr │ │ │ ├── responds_to_spec.cr │ │ │ ├── return_spec.cr │ │ │ ├── sizeof_spec.cr │ │ │ ├── special_vars_spec.cr │ │ │ ├── splat_spec.cr │ │ │ ├── ssa_spec.cr │ │ │ ├── struct_spec.cr │ │ │ ├── super_spec.cr │ │ │ ├── target_spec.cr │ │ │ ├── thread_local_spec.cr │ │ │ ├── tuple_spec.cr │ │ │ ├── type_declaration_spec.cr │ │ │ ├── uninitialized_spec.cr │ │ │ ├── union_type_spec.cr │ │ │ ├── until_spec.cr │ │ │ ├── var_spec.cr │ │ │ ├── virtual_spec.cr │ │ │ ├── void_spec.cr │ │ │ ├── while_spec.cr │ │ │ └── yield_with_scope_spec.cr │ │ ├── compiler_spec.cr │ │ ├── config_spec.cr │ │ ├── crystal/ │ │ │ ├── commands/ │ │ │ │ └── clear_cache_spec.cr │ │ │ ├── tools/ │ │ │ │ ├── context_spec.cr │ │ │ │ ├── doc/ │ │ │ │ │ ├── directives_spec.cr │ │ │ │ │ ├── doc_renderer_spec.cr │ │ │ │ │ ├── generator_spec.cr │ │ │ │ │ ├── macro_spec.cr │ │ │ │ │ ├── method_spec.cr │ │ │ │ │ ├── project_info_spec.cr │ │ │ │ │ └── type_spec.cr │ │ │ │ ├── doc_spec.cr │ │ │ │ ├── expand_spec.cr │ │ │ │ ├── flags_spec.cr │ │ │ │ ├── format_spec.cr │ │ │ │ ├── hierarchy_spec.cr │ │ │ │ ├── implementations_spec.cr │ │ │ │ ├── init_spec.cr │ │ │ │ ├── macro_code_coverage_spec.cr │ │ │ │ ├── playground_spec.cr │ │ │ │ ├── repl_spec.cr │ │ │ │ ├── table_print_spec.cr │ │ │ │ └── unreachable_spec.cr │ │ │ └── types_spec.cr │ │ ├── crystal_path/ │ │ │ └── crystal_path_spec.cr │ │ ├── data/ │ │ │ ├── args_test │ │ │ ├── build │ │ │ ├── compiler_sample │ │ │ ├── crystal_path/ │ │ │ │ ├── foo.cr/ │ │ │ │ │ └── foo.cr │ │ │ │ ├── other_test_files/ │ │ │ │ │ └── other_test_files.cr │ │ │ │ ├── simple.cr │ │ │ │ └── test_files/ │ │ │ │ ├── file_one.cr │ │ │ │ ├── file_two.cr │ │ │ │ ├── src/ │ │ │ │ │ ├── file_three.cr │ │ │ │ │ ├── test_files/ │ │ │ │ │ │ ├── another/ │ │ │ │ │ │ │ └── another.cr │ │ │ │ │ │ └── file_four.cr │ │ │ │ │ ├── test_files.cr │ │ │ │ │ └── yet_another/ │ │ │ │ │ └── yet_another.cr │ │ │ │ └── test_folder/ │ │ │ │ ├── file_three.cr │ │ │ │ ├── not_a_crystal_file.txt │ │ │ │ └── test_folder.cr │ │ │ ├── ffi/ │ │ │ │ └── sum.c │ │ │ ├── interpreter/ │ │ │ │ └── sum.c │ │ │ ├── loader/ │ │ │ │ ├── bar.c │ │ │ │ ├── foo.c │ │ │ │ └── foo2.c │ │ │ └── visibility.h │ │ ├── ffi/ │ │ │ └── ffi_spec.cr │ │ ├── formatter/ │ │ │ └── formatter_spec.cr │ │ ├── interpreter/ │ │ │ ├── autocast_spec.cr │ │ │ ├── blocks_spec.cr │ │ │ ├── bugs_spec.cr │ │ │ ├── calls_spec.cr │ │ │ ├── casts_spec.cr │ │ │ ├── class_vars_spec.cr │ │ │ ├── classes_spec.cr │ │ │ ├── closures_spec.cr │ │ │ ├── constants_spec.cr │ │ │ ├── control_flow_spec.cr │ │ │ ├── enum_spec.cr │ │ │ ├── exceptions_spec.cr │ │ │ ├── extern_spec.cr │ │ │ ├── integration_spec.cr │ │ │ ├── is_a_spec.cr │ │ │ ├── lib_spec.cr │ │ │ ├── multidispatch_spec.cr │ │ │ ├── named_tuple_spec.cr │ │ │ ├── pointers_spec.cr │ │ │ ├── primitives_spec.cr │ │ │ ├── procs_spec.cr │ │ │ ├── responds_to_spec.cr │ │ │ ├── sizeof_spec.cr │ │ │ ├── spec_helper.cr │ │ │ ├── special_vars_spec.cr │ │ │ ├── structs_spec.cr │ │ │ ├── symbol_spec.cr │ │ │ ├── tuple_spec.cr │ │ │ ├── typeof_spec.cr │ │ │ ├── types_spec.cr │ │ │ └── unions_spec.cr │ │ ├── interpreter_spec.cr │ │ ├── lexer/ │ │ │ ├── lexer_comment_spec.cr │ │ │ ├── lexer_doc_spec.cr │ │ │ ├── lexer_macro_spec.cr │ │ │ ├── lexer_objects/ │ │ │ │ └── strings.cr │ │ │ ├── lexer_spec.cr │ │ │ ├── lexer_string_array_spec.cr │ │ │ ├── lexer_string_spec.cr │ │ │ └── location_spec.cr │ │ ├── loader/ │ │ │ ├── msvc_spec.cr │ │ │ ├── spec_helper.cr │ │ │ └── unix_spec.cr │ │ ├── macro/ │ │ │ ├── macro_expander_spec.cr │ │ │ └── macro_methods_spec.cr │ │ ├── normalize/ │ │ │ ├── and_spec.cr │ │ │ ├── array_literal_spec.cr │ │ │ ├── block_spec.cr │ │ │ ├── case_spec.cr │ │ │ ├── chained_comparisons_spec.cr │ │ │ ├── def_spec.cr │ │ │ ├── expressions_spec.cr │ │ │ ├── hash_literal_spec.cr │ │ │ ├── multi_assign_spec.cr │ │ │ ├── op_assign_spec.cr │ │ │ ├── or_spec.cr │ │ │ ├── proc_pointer_spec.cr │ │ │ ├── range_literal_spec.cr │ │ │ ├── regex_spec.cr │ │ │ ├── return_next_break_spec.cr │ │ │ ├── select_spec.cr │ │ │ ├── string_interpolation_spec.cr │ │ │ ├── unless_spec.cr │ │ │ └── until_spec.cr │ │ ├── parser/ │ │ │ ├── parser_doc_spec.cr │ │ │ ├── parser_spec.cr │ │ │ ├── to_s_spec.cr │ │ │ └── warnings_spec.cr │ │ ├── semantic/ │ │ │ ├── abstract_def_spec.cr │ │ │ ├── alias_spec.cr │ │ │ ├── annotation_spec.cr │ │ │ ├── array_spec.cr │ │ │ ├── automatic_cast_spec.cr │ │ │ ├── block_spec.cr │ │ │ ├── c_enum_spec.cr │ │ │ ├── c_struct_spec.cr │ │ │ ├── c_type_spec.cr │ │ │ ├── c_union_spec.cr │ │ │ ├── call_error_spec.cr │ │ │ ├── case_spec.cr │ │ │ ├── cast_spec.cr │ │ │ ├── class_spec.cr │ │ │ ├── class_var_spec.cr │ │ │ ├── cleanup_spec.cr │ │ │ ├── closure_spec.cr │ │ │ ├── concrete_types_spec.cr │ │ │ ├── const_spec.cr │ │ │ ├── def_overload_spec.cr │ │ │ ├── def_spec.cr │ │ │ ├── did_you_mean_spec.cr │ │ │ ├── doc_spec.cr │ │ │ ├── double_splat_spec.cr │ │ │ ├── enum_spec.cr │ │ │ ├── exception_spec.cr │ │ │ ├── extern_spec.cr │ │ │ ├── external_internal_spec.cr │ │ │ ├── fun_spec.cr │ │ │ ├── generic_class_spec.cr │ │ │ ├── hooks_spec.cr │ │ │ ├── if_spec.cr │ │ │ ├── initialize_spec.cr │ │ │ ├── instance_var_spec.cr │ │ │ ├── is_a_spec.cr │ │ │ ├── lib_spec.cr │ │ │ ├── macro_overload_spec.cr │ │ │ ├── macro_spec.cr │ │ │ ├── metaclass_spec.cr │ │ │ ├── method_missing_spec.cr │ │ │ ├── module_spec.cr │ │ │ ├── multi_assign_spec.cr │ │ │ ├── named_args_spec.cr │ │ │ ├── named_tuple_spec.cr │ │ │ ├── new_spec.cr │ │ │ ├── nil_spec.cr │ │ │ ├── nilable_cast_spec.cr │ │ │ ├── nilable_instance_var_spec.cr │ │ │ ├── no_return_spec.cr │ │ │ ├── not_spec.cr │ │ │ ├── offsetof_spec.cr │ │ │ ├── pointer_spec.cr │ │ │ ├── previous_def_spec.cr │ │ │ ├── primitives_spec.cr │ │ │ ├── private_spec.cr │ │ │ ├── proc_spec.cr │ │ │ ├── recursive_struct_check_spec.cr │ │ │ ├── reference_storage_spec.cr │ │ │ ├── require_spec.cr │ │ │ ├── responds_to_spec.cr │ │ │ ├── restrictions_augmenter_spec.cr │ │ │ ├── restrictions_spec.cr │ │ │ ├── return_spec.cr │ │ │ ├── sizeof_spec.cr │ │ │ ├── special_vars_spec.cr │ │ │ ├── splat_spec.cr │ │ │ ├── ssa_spec.cr │ │ │ ├── static_array_spec.cr │ │ │ ├── struct_spec.cr │ │ │ ├── super_spec.cr │ │ │ ├── tuple_spec.cr │ │ │ ├── uninitialized_spec.cr │ │ │ ├── union_spec.cr │ │ │ ├── var_spec.cr │ │ │ ├── virtual_metaclass_spec.cr │ │ │ ├── virtual_spec.cr │ │ │ ├── visibility_modifiers_spec.cr │ │ │ ├── warnings_spec.cr │ │ │ ├── while_spec.cr │ │ │ └── yield_with_scope_spec.cr │ │ ├── spec_helper.cr │ │ └── util_spec.cr │ ├── compiler_spec.cr │ ├── debug/ │ │ ├── arrays.cr │ │ ├── blocks.cr │ │ ├── driver.cr │ │ ├── extern_unions.cr │ │ ├── large_enums.cr │ │ ├── strings.cr │ │ ├── test.sh │ │ └── top_level.cr │ ├── generate_wasm32_spec.sh │ ├── llvm-ir/ │ │ ├── argless-initialize-debug-loc.cr │ │ ├── assign-unions.cr │ │ ├── cast-unions.cr │ │ ├── class-var-read-debug-loc.cr │ │ ├── const-read-debug-loc.cr │ │ ├── memcpy.cr │ │ ├── memset.cr │ │ ├── pass-closure-to-c-debug-loc.cr │ │ ├── proc-call-debug-loc.cr │ │ ├── proc-pointer-debug-loc.cr │ │ ├── test.sh │ │ ├── virtual-class-var-read-debug-loc.cr │ │ └── virtual-metaclass-var-read-debug-loc.cr │ ├── manual/ │ │ ├── badssl_spec.cr │ │ ├── digest_large_file_spec.cr │ │ ├── find_executable_spec.cr │ │ ├── gzip_large_file_spec.cr │ │ ├── hash_large_spec.cr │ │ ├── https_client_spec.cr │ │ ├── string_normalize_spec.cr │ │ ├── string_to_f32_spec.cr │ │ └── string_to_f_supplemental_spec.cr │ ├── primitives/ │ │ ├── external_command_spec.cr │ │ ├── float_spec.cr │ │ ├── int_spec.cr │ │ ├── pointer_spec.cr │ │ ├── reference_spec.cr │ │ ├── slice_spec.cr │ │ └── struct_spec.cr │ ├── primitives_spec.cr │ ├── spec_helper.cr │ ├── std/ │ │ ├── array_spec.cr │ │ ├── atomic_spec.cr │ │ ├── base64_spec.cr │ │ ├── benchmark_spec.cr │ │ ├── big/ │ │ │ ├── big_decimal_spec.cr │ │ │ ├── big_float_spec.cr │ │ │ ├── big_int_spec.cr │ │ │ ├── big_rational_spec.cr │ │ │ └── number_spec.cr │ │ ├── bit_array_spec.cr │ │ ├── bool_spec.cr │ │ ├── box_spec.cr │ │ ├── channel_spec.cr │ │ ├── char/ │ │ │ └── reader_spec.cr │ │ ├── char_spec.cr │ │ ├── class_spec.cr │ │ ├── colorize_spec.cr │ │ ├── comparable_spec.cr │ │ ├── complex_spec.cr │ │ ├── compress/ │ │ │ ├── deflate/ │ │ │ │ └── deflate_spec.cr │ │ │ ├── gzip/ │ │ │ │ └── gzip_spec.cr │ │ │ ├── zip/ │ │ │ │ ├── zip_file_spec.cr │ │ │ │ └── zip_spec.cr │ │ │ └── zlib/ │ │ │ ├── reader_spec.cr │ │ │ ├── stress_spec.cr │ │ │ └── writer_spec.cr │ │ ├── concurrent/ │ │ │ └── select_spec.cr │ │ ├── concurrent_spec.cr │ │ ├── crypto/ │ │ │ ├── bcrypt/ │ │ │ │ ├── base64_spec.cr │ │ │ │ └── password_spec.cr │ │ │ ├── bcrypt_spec.cr │ │ │ ├── blowfish_spec.cr │ │ │ └── subtle_spec.cr │ │ ├── crystal/ │ │ │ ├── compiler_rt/ │ │ │ │ ├── ashlti3_spec.cr │ │ │ │ ├── ashrti3_spec.cr │ │ │ │ ├── divmod128_spec.cr │ │ │ │ ├── fixint_spec.cr │ │ │ │ ├── float_spec.cr │ │ │ │ ├── lshrti3_spec.cr │ │ │ │ ├── mulodi4_spec.cr │ │ │ │ ├── mulosi4_spec.cr │ │ │ │ ├── muloti4_spec.cr │ │ │ │ ├── multi3_spec.cr │ │ │ │ ├── powidf2_spec.cr │ │ │ │ ├── powisf2_spec.cr │ │ │ │ └── spec_helper.cr │ │ │ ├── digest/ │ │ │ │ ├── md5_spec.cr │ │ │ │ └── sha1_spec.cr │ │ │ ├── event_loop/ │ │ │ │ ├── polling/ │ │ │ │ │ ├── arena_spec.cr │ │ │ │ │ ├── poll_descriptor_spec.cr │ │ │ │ │ └── waiters_spec.cr │ │ │ │ └── timers_spec.cr │ │ │ ├── fd_lock_spec.cr │ │ │ ├── hasher_spec.cr │ │ │ ├── pointer_linked_list_spec.cr │ │ │ ├── pointer_pairing_heap_spec.cr │ │ │ ├── syntax_highlighter/ │ │ │ │ ├── colorize_spec.cr │ │ │ │ └── html_spec.cr │ │ │ ├── system/ │ │ │ │ └── cpucount_spec.cr │ │ │ └── system_spec.cr │ │ ├── csv/ │ │ │ ├── csv_build_spec.cr │ │ │ ├── csv_lex_spec.cr │ │ │ ├── csv_parse_spec.cr │ │ │ └── csv_spec.cr │ │ ├── data/ │ │ │ ├── android_tzdata │ │ │ ├── argf_test_file_1.txt │ │ │ ├── argf_test_file_2.txt │ │ │ ├── argf_test_file_3.xml │ │ │ ├── backtrace_sample │ │ │ ├── blank_test_file.txt │ │ │ ├── cipher_spec.ciphertext │ │ │ ├── collect_within_ensure │ │ │ ├── crash_backtrace_sample │ │ │ ├── dir/ │ │ │ │ ├── dots/ │ │ │ │ │ ├── .dot.hidden │ │ │ │ │ └── .hidden/ │ │ │ │ │ └── f1.txt │ │ │ │ ├── f1.txt │ │ │ │ ├── f2.txt │ │ │ │ ├── f3.txx │ │ │ │ ├── g2.txt │ │ │ │ ├── subdir/ │ │ │ │ │ ├── f1.txt │ │ │ │ │ └── subdir2/ │ │ │ │ │ └── f2.txt │ │ │ │ └── subdir2/ │ │ │ │ └── .gitkeep │ │ │ ├── exception_backtrace_sample │ │ │ ├── io_data_incomplete_multibyte_sequence.txt │ │ │ ├── io_data_incomplete_multibyte_sequence_2.txt │ │ │ ├── large_single_line_string.txt │ │ │ ├── mime.types │ │ │ ├── openssl/ │ │ │ │ ├── openssl.crt │ │ │ │ └── openssl.key │ │ │ ├── static_file_handler/ │ │ │ │ ├── empty.txt │ │ │ │ ├── foo/ │ │ │ │ │ └── bar.txt │ │ │ │ ├── range.txt │ │ │ │ └── test.txt │ │ │ ├── test_file.ini │ │ │ ├── test_file.txt │ │ │ ├── test_template.ecr │ │ │ ├── test_template2.ecr │ │ │ ├── test_template3.ecr │ │ │ ├── test_template4.ecr │ │ │ ├── test_template5.ecr │ │ │ ├── test_template6.ecr │ │ │ ├── test_template7.ecr │ │ │ └── zoneinfo/ │ │ │ └── Foo/ │ │ │ ├── Bar │ │ │ └── invalid │ │ ├── deque_spec.cr │ │ ├── digest/ │ │ │ ├── adler32_spec.cr │ │ │ ├── crc32_spec.cr │ │ │ ├── io_digest_spec.cr │ │ │ ├── md5_spec.cr │ │ │ ├── sha1_spec.cr │ │ │ ├── sha256_spec.cr │ │ │ ├── sha512_spec.cr │ │ │ └── spec_helper.cr │ │ ├── dir_spec.cr │ │ ├── double_spec.cr │ │ ├── ecr/ │ │ │ ├── ecr_lexer_spec.cr │ │ │ └── ecr_spec.cr │ │ ├── enum_spec.cr │ │ ├── enumerable_spec.cr │ │ ├── env_spec.cr │ │ ├── errno_spec.cr │ │ ├── exception/ │ │ │ └── call_stack_spec.cr │ │ ├── exception_spec.cr │ │ ├── fiber/ │ │ │ ├── execution_context/ │ │ │ │ ├── global_queue_spec.cr │ │ │ │ ├── parallel_spec.cr │ │ │ │ ├── runnables_spec.cr │ │ │ │ └── spec_helper.cr │ │ │ └── list_spec.cr │ │ ├── fiber_spec.cr │ │ ├── file/ │ │ │ ├── match-fast-glob_spec.cr │ │ │ ├── match_spec.cr │ │ │ └── tempfile_spec.cr │ │ ├── file_spec.cr │ │ ├── file_utils_spec.cr │ │ ├── float_printer/ │ │ │ ├── diy_fp_spec.cr │ │ │ ├── grisu3_spec.cr │ │ │ ├── hexfloat_spec.cr │ │ │ ├── ieee_spec.cr │ │ │ ├── ryu_printf_spec.cr │ │ │ ├── ryu_printf_test_cases.cr │ │ │ └── shortest_spec.cr │ │ ├── float_spec.cr │ │ ├── gc_spec.cr │ │ ├── hash_spec.cr │ │ ├── html_spec.cr │ │ ├── http/ │ │ │ ├── chunked_content_spec.cr │ │ │ ├── client/ │ │ │ │ ├── client_spec.cr │ │ │ │ └── response_spec.cr │ │ │ ├── cookie_spec.cr │ │ │ ├── cookies_spec.cr │ │ │ ├── formdata/ │ │ │ │ ├── builder_spec.cr │ │ │ │ └── parser_spec.cr │ │ │ ├── formdata_spec.cr │ │ │ ├── headers_spec.cr │ │ │ ├── http_spec.cr │ │ │ ├── params_spec.cr │ │ │ ├── request_spec.cr │ │ │ ├── server/ │ │ │ │ ├── handlers/ │ │ │ │ │ ├── compress_handler_spec.cr │ │ │ │ │ ├── error_handler_spec.cr │ │ │ │ │ ├── handler_spec.cr │ │ │ │ │ ├── log_handler_spec.cr │ │ │ │ │ ├── static_file_handler_spec.cr │ │ │ │ │ └── websocket_handler_spec.cr │ │ │ │ ├── request_processor_spec.cr │ │ │ │ ├── response_spec.cr │ │ │ │ └── server_spec.cr │ │ │ ├── spec_helper.cr │ │ │ ├── status_spec.cr │ │ │ └── web_socket_spec.cr │ │ ├── humanize_spec.cr │ │ ├── indexable/ │ │ │ └── mutable_spec.cr │ │ ├── indexable_spec.cr │ │ ├── ini_spec.cr │ │ ├── int_spec.cr │ │ ├── io/ │ │ │ ├── argf_spec.cr │ │ │ ├── buffered_spec.cr │ │ │ ├── byte_format_spec.cr │ │ │ ├── delimited_spec.cr │ │ │ ├── file_descriptor_spec.cr │ │ │ ├── hexdump_spec.cr │ │ │ ├── io_spec.cr │ │ │ ├── memory_spec.cr │ │ │ ├── multi_writer_spec.cr │ │ │ ├── sized_spec.cr │ │ │ └── stapled_spec.cr │ │ ├── iterator_spec.cr │ │ ├── json/ │ │ │ ├── any_spec.cr │ │ │ ├── builder_spec.cr │ │ │ ├── lexer_spec.cr │ │ │ ├── parser_spec.cr │ │ │ ├── pull_parser_spec.cr │ │ │ ├── serializable_spec.cr │ │ │ └── serialization_spec.cr │ │ ├── kernel_spec.cr │ │ ├── levenshtein_spec.cr │ │ ├── llvm/ │ │ │ ├── llvm_spec.cr │ │ │ └── type_spec.cr │ │ ├── log/ │ │ │ ├── broadcast_backend_spec.cr │ │ │ ├── builder_spec.cr │ │ │ ├── context_spec.cr │ │ │ ├── dispatch_spec.cr │ │ │ ├── env_config_spec.cr │ │ │ ├── format_spec.cr │ │ │ ├── io_backend_spec.cr │ │ │ ├── log_spec.cr │ │ │ ├── main_spec.cr │ │ │ ├── metadata_spec.cr │ │ │ └── spec_spec.cr │ │ ├── math_spec.cr │ │ ├── mime/ │ │ │ ├── media_type_spec.cr │ │ │ ├── multipart/ │ │ │ │ ├── builder_spec.cr │ │ │ │ └── parser_spec.cr │ │ │ └── multipart_spec.cr │ │ ├── mime_spec.cr │ │ ├── mutex_spec.cr │ │ ├── named_tuple_spec.cr │ │ ├── number_spec.cr │ │ ├── oauth/ │ │ │ ├── access_token_spec.cr │ │ │ ├── authorization_header_spec.cr │ │ │ ├── consumer_spec.cr │ │ │ ├── request_token_spec.cr │ │ │ └── signature_spec.cr │ │ ├── oauth2/ │ │ │ ├── access_token_spec.cr │ │ │ ├── client_spec.cr │ │ │ └── session_spec.cr │ │ ├── object_spec.cr │ │ ├── openssl/ │ │ │ ├── cipher_spec.cr │ │ │ ├── digest_spec.cr │ │ │ ├── hmac_spec.cr │ │ │ ├── pkcs5_spec.cr │ │ │ ├── ssl/ │ │ │ │ ├── context_spec.cr │ │ │ │ ├── hostname_validation_spec.cr │ │ │ │ ├── server_spec.cr │ │ │ │ └── socket_spec.cr │ │ │ └── x509/ │ │ │ ├── certificate_spec.cr │ │ │ └── name_spec.cr │ │ ├── option_parser_spec.cr │ │ ├── path_spec.cr │ │ ├── pointer/ │ │ │ └── appender_spec.cr │ │ ├── pointer_spec.cr │ │ ├── pp_spec.cr │ │ ├── pretty_print_spec.cr │ │ ├── proc_spec.cr │ │ ├── process/ │ │ │ ├── exit_reason_spec.cr │ │ │ ├── find_executable_spec.cr │ │ │ ├── status_spec.cr │ │ │ └── utils_spec.cr │ │ ├── process_spec.cr │ │ ├── raise_spec.cr │ │ ├── random/ │ │ │ ├── isaac_spec.cr │ │ │ ├── pcg32_spec.cr │ │ │ └── secure_spec.cr │ │ ├── random_spec.cr │ │ ├── range_spec.cr │ │ ├── record_spec.cr │ │ ├── reference_spec.cr │ │ ├── regex/ │ │ │ └── match_data_spec.cr │ │ ├── regex_spec.cr │ │ ├── semantic_version_spec.cr │ │ ├── set_spec.cr │ │ ├── signal_spec.cr │ │ ├── slice_spec.cr │ │ ├── socket/ │ │ │ ├── address_spec.cr │ │ │ ├── addrinfo_spec.cr │ │ │ ├── socket_spec.cr │ │ │ ├── spec_helper.cr │ │ │ ├── tcp_server_spec.cr │ │ │ ├── tcp_socket_spec.cr │ │ │ ├── udp_socket_spec.cr │ │ │ ├── unix_server_spec.cr │ │ │ └── unix_socket_spec.cr │ │ ├── spec/ │ │ │ ├── context_spec.cr │ │ │ ├── expectations_spec.cr │ │ │ ├── filters_spec.cr │ │ │ ├── helpers/ │ │ │ │ └── iterate_spec.cr │ │ │ ├── hooks_spec.cr │ │ │ ├── junit_formatter_spec.cr │ │ │ ├── list_tags_spec.cr │ │ │ ├── spec_helper.cr │ │ │ └── tap_formatter_spec.cr │ │ ├── spec_helper.cr │ │ ├── spec_spec.cr │ │ ├── sprintf_spec.cr │ │ ├── static_array_spec.cr │ │ ├── string/ │ │ │ ├── grapheme_break_spec.cr │ │ │ ├── grapheme_spec.cr │ │ │ ├── spec_helper.cr │ │ │ └── utf16_spec.cr │ │ ├── string_builder_spec.cr │ │ ├── string_pool_spec.cr │ │ ├── string_scanner_spec.cr │ │ ├── string_spec.cr │ │ ├── struct_spec.cr │ │ ├── symbol_spec.cr │ │ ├── sync/ │ │ │ ├── condition_variable_spec.cr │ │ │ ├── exclusive_spec.cr │ │ │ ├── mutex_spec.cr │ │ │ ├── rw_lock_spec.cr │ │ │ ├── shared_spec.cr │ │ │ └── spec_helper.cr │ │ ├── syscall_spec.cr │ │ ├── system/ │ │ │ ├── group_spec.cr │ │ │ └── user_spec.cr │ │ ├── system_error_spec.cr │ │ ├── system_spec.cr │ │ ├── thread/ │ │ │ ├── condition_variable_spec.cr │ │ │ └── mutex_spec.cr │ │ ├── thread_spec.cr │ │ ├── time/ │ │ │ ├── custom_formats_spec.cr │ │ │ ├── format_spec.cr │ │ │ ├── instant_spec.cr │ │ │ ├── location_spec.cr │ │ │ ├── span_spec.cr │ │ │ └── time_spec.cr │ │ ├── tuple_spec.cr │ │ ├── uint_spec.cr │ │ ├── uri/ │ │ │ ├── json_spec.cr │ │ │ ├── params/ │ │ │ │ ├── from_www_form_spec.cr │ │ │ │ ├── serializable_spec.cr │ │ │ │ └── to_www_form_spec.cr │ │ │ ├── params_spec.cr │ │ │ └── punycode_spec.cr │ │ ├── uri_spec.cr │ │ ├── uuid/ │ │ │ ├── json_spec.cr │ │ │ └── yaml_spec.cr │ │ ├── uuid_spec.cr │ │ ├── va_list_spec.cr │ │ ├── wait_group_spec.cr │ │ ├── weak_ref_spec.cr │ │ ├── winerror_spec.cr │ │ ├── xml/ │ │ │ ├── builder_spec.cr │ │ │ ├── html_spec.cr │ │ │ ├── reader_spec.cr │ │ │ ├── xml_spec.cr │ │ │ └── xpath_spec.cr │ │ └── yaml/ │ │ ├── any_spec.cr │ │ ├── builder_spec.cr │ │ ├── nodes/ │ │ │ ├── builder_spec.cr │ │ │ └── parser_spec.cr │ │ ├── schema/ │ │ │ ├── core_spec.cr │ │ │ └── fail_safe_spec.cr │ │ ├── serializable_spec.cr │ │ ├── serialization_spec.cr │ │ ├── yaml_pull_parser_spec.cr │ │ └── yaml_spec.cr │ ├── std_spec.cr │ ├── support/ │ │ ├── channel.cr │ │ ├── env.cr │ │ ├── fibers.cr │ │ ├── finalize.cr │ │ ├── interpreted.cr │ │ ├── io.cr │ │ ├── mt_abort_timeout.cr │ │ ├── number.cr │ │ ├── retry.cr │ │ ├── ssl.cr │ │ ├── string.cr │ │ ├── syntax.cr │ │ ├── tempfile.cr │ │ ├── thread.cr │ │ ├── time.cr │ │ ├── wait_for.cr │ │ ├── wasm32.cr │ │ └── win32.cr │ ├── syntax_spec.cr │ └── wasm32_std_spec.cr └── src/ ├── VERSION ├── annotations.cr ├── array.cr ├── atomic.cr ├── base64.cr ├── benchmark/ │ ├── bm.cr │ └── ips.cr ├── benchmark.cr ├── big/ │ ├── big_decimal.cr │ ├── big_float.cr │ ├── big_int.cr │ ├── big_rational.cr │ ├── json.cr │ ├── lib_gmp.cr │ ├── number.cr │ └── yaml.cr ├── big.cr ├── bit_array.cr ├── bool.cr ├── box.cr ├── channel/ │ ├── select/ │ │ ├── select_action.cr │ │ └── timeout_action.cr │ └── select.cr ├── channel.cr ├── char/ │ └── reader.cr ├── char.cr ├── class.cr ├── colorize.cr ├── comparable.cr ├── compiler/ │ ├── crystal/ │ │ ├── annotatable.cr │ │ ├── codegen/ │ │ │ ├── abi/ │ │ │ │ ├── aarch64.cr │ │ │ │ ├── arm.cr │ │ │ │ ├── avr.cr │ │ │ │ ├── wasm32.cr │ │ │ │ ├── x86.cr │ │ │ │ ├── x86_64.cr │ │ │ │ └── x86_win64.cr │ │ │ ├── abi.cr │ │ │ ├── asm.cr │ │ │ ├── ast.cr │ │ │ ├── cache_dir.cr │ │ │ ├── call.cr │ │ │ ├── cast.cr │ │ │ ├── class_var.cr │ │ │ ├── codegen.cr │ │ │ ├── cond.cr │ │ │ ├── const.cr │ │ │ ├── context.cr │ │ │ ├── crystal_llvm_builder.cr │ │ │ ├── debug.cr │ │ │ ├── dump_type_info.cr │ │ │ ├── exception.cr │ │ │ ├── experimental.cr │ │ │ ├── fun.cr │ │ │ ├── link.cr │ │ │ ├── llvm_builder_helper.cr │ │ │ ├── llvm_id.cr │ │ │ ├── llvm_typer.cr │ │ │ ├── match.cr │ │ │ ├── once.cr │ │ │ ├── phi.cr │ │ │ ├── primitives.cr │ │ │ ├── target.cr │ │ │ ├── type_id.cr │ │ │ ├── types.cr │ │ │ └── unions.cr │ │ ├── command/ │ │ │ ├── clear_cache.cr │ │ │ ├── cursor.cr │ │ │ ├── docs.cr │ │ │ ├── env.cr │ │ │ ├── eval.cr │ │ │ ├── format.cr │ │ │ ├── playground.cr │ │ │ ├── repl.cr │ │ │ └── spec.cr │ │ ├── command.cr │ │ ├── compiler.cr │ │ ├── config.cr │ │ ├── crystal_path.cr │ │ ├── error.cr │ │ ├── exception.cr │ │ ├── ffi/ │ │ │ ├── call_interface.cr │ │ │ ├── closure.cr │ │ │ ├── ffi.cr │ │ │ ├── lib_ffi.cr │ │ │ └── type.cr │ │ ├── formatter.cr │ │ ├── interpreter/ │ │ │ ├── c.cr │ │ │ ├── cast.cr │ │ │ ├── class_vars.cr │ │ │ ├── closure.cr │ │ │ ├── closure_context.cr │ │ │ ├── compiled_block.cr │ │ │ ├── compiled_def.cr │ │ │ ├── compiled_instructions.cr │ │ │ ├── compiler.cr │ │ │ ├── constants.cr │ │ │ ├── context.cr │ │ │ ├── debug.cr │ │ │ ├── disassembler.cr │ │ │ ├── escaping_exception.cr │ │ │ ├── ffi_closure_context.cr │ │ │ ├── instruction.cr │ │ │ ├── instructions.cr │ │ │ ├── interpreter.cr │ │ │ ├── lib_function.cr │ │ │ ├── local_vars.cr │ │ │ ├── local_vars_gatherer.cr │ │ │ ├── multidispatch.cr │ │ │ ├── op_code.cr │ │ │ ├── primitives.cr │ │ │ ├── pry_reader.cr │ │ │ ├── repl.cr │ │ │ ├── repl_reader.cr │ │ │ ├── to_bool.cr │ │ │ └── value.cr │ │ ├── interpreter.cr │ │ ├── loader/ │ │ │ ├── mingw.cr │ │ │ ├── msvc.cr │ │ │ └── unix.cr │ │ ├── loader.cr │ │ ├── macros/ │ │ │ ├── interpreter.cr │ │ │ ├── macros.cr │ │ │ ├── methods.cr │ │ │ └── types.cr │ │ ├── macros.cr │ │ ├── program.cr │ │ ├── progress_tracker.cr │ │ ├── semantic/ │ │ │ ├── abstract_def_checker.cr │ │ │ ├── ast.cr │ │ │ ├── bindings.cr │ │ │ ├── call.cr │ │ │ ├── call_error.cr │ │ │ ├── class_vars_initializer_visitor.cr │ │ │ ├── cleanup_transformer.cr │ │ │ ├── conversions.cr │ │ │ ├── cover.cr │ │ │ ├── default_arguments.cr │ │ │ ├── exception.cr │ │ │ ├── exhaustiveness_checker.cr │ │ │ ├── filters.cr │ │ │ ├── fix_missing_types.cr │ │ │ ├── flags.cr │ │ │ ├── hooks.cr │ │ │ ├── instance_vars_initializer_visitor.cr │ │ │ ├── lib.cr │ │ │ ├── literal_expander.cr │ │ │ ├── main_visitor.cr │ │ │ ├── match.cr │ │ │ ├── math_interpreter.cr │ │ │ ├── method_lookup.cr │ │ │ ├── method_missing.cr │ │ │ ├── new.cr │ │ │ ├── normalizer.cr │ │ │ ├── path_lookup.cr │ │ │ ├── recursive_struct_checker.cr │ │ │ ├── restrictions.cr │ │ │ ├── restrictions_augmenter.cr │ │ │ ├── semantic_visitor.cr │ │ │ ├── suggestions.cr │ │ │ ├── to_s.cr │ │ │ ├── top_level_visitor.cr │ │ │ ├── transformer.cr │ │ │ ├── type_declaration_processor.cr │ │ │ ├── type_declaration_visitor.cr │ │ │ ├── type_guess_visitor.cr │ │ │ ├── type_intersect.cr │ │ │ ├── type_lookup.cr │ │ │ ├── type_merge.cr │ │ │ ├── type_to_restriction.cr │ │ │ └── warnings.cr │ │ ├── semantic.cr │ │ ├── syntax/ │ │ │ ├── ast.cr │ │ │ ├── exception.cr │ │ │ ├── lexer.cr │ │ │ ├── location.cr │ │ │ ├── parser.cr │ │ │ ├── to_s.cr │ │ │ ├── token.cr │ │ │ ├── transformer.cr │ │ │ ├── virtual_file.cr │ │ │ └── visitor.cr │ │ ├── syntax.cr │ │ ├── tools/ │ │ │ ├── context.cr │ │ │ ├── dependencies.cr │ │ │ ├── doc/ │ │ │ │ ├── constant.cr │ │ │ │ ├── generator.cr │ │ │ │ ├── html/ │ │ │ │ │ ├── 404.html │ │ │ │ │ ├── _head.html │ │ │ │ │ ├── _list_items.html │ │ │ │ │ ├── _macros_inherited.html │ │ │ │ │ ├── _method_detail.html │ │ │ │ │ ├── _method_summary.html │ │ │ │ │ ├── _methods_inherited.html │ │ │ │ │ ├── _other_types.html │ │ │ │ │ ├── _sidebar.html │ │ │ │ │ ├── css/ │ │ │ │ │ │ └── style.css │ │ │ │ │ ├── js/ │ │ │ │ │ │ ├── _navigator.js │ │ │ │ │ │ ├── _search.js │ │ │ │ │ │ ├── _usage-modal.js │ │ │ │ │ │ ├── _versions.js │ │ │ │ │ │ └── doc.js │ │ │ │ │ ├── main.html │ │ │ │ │ ├── sitemap.xml │ │ │ │ │ └── type.html │ │ │ │ ├── item.cr │ │ │ │ ├── macro.cr │ │ │ │ ├── main.cr │ │ │ │ ├── markd_doc_renderer.cr │ │ │ │ ├── method.cr │ │ │ │ ├── project_info.cr │ │ │ │ ├── relative_location.cr │ │ │ │ ├── templates.cr │ │ │ │ ├── to_json.cr │ │ │ │ └── type.cr │ │ │ ├── doc.cr │ │ │ ├── expand.cr │ │ │ ├── flags.cr │ │ │ ├── formatter.cr │ │ │ ├── git.cr │ │ │ ├── implementations.cr │ │ │ ├── init/ │ │ │ │ └── template/ │ │ │ │ ├── editorconfig.ecr │ │ │ │ ├── example.cr.ecr │ │ │ │ ├── example_spec.cr.ecr │ │ │ │ ├── gitignore.ecr │ │ │ │ ├── license.ecr │ │ │ │ ├── readme.md.ecr │ │ │ │ ├── shard.yml.ecr │ │ │ │ └── spec_helper.cr.ecr │ │ │ ├── init.cr │ │ │ ├── macro_code_coverage.cr │ │ │ ├── playground/ │ │ │ │ ├── agent.cr │ │ │ │ ├── agent_instrumentor_transformer.cr │ │ │ │ ├── public/ │ │ │ │ │ ├── application.css │ │ │ │ │ ├── application.js │ │ │ │ │ ├── session.js │ │ │ │ │ ├── settings.js │ │ │ │ │ └── vendor/ │ │ │ │ │ ├── REUSE.toml │ │ │ │ │ ├── ansi_up-1.3.0/ │ │ │ │ │ │ ├── ansi_up.js │ │ │ │ │ │ └── theme.css │ │ │ │ │ ├── codemirror-5.38.0/ │ │ │ │ │ │ ├── addon/ │ │ │ │ │ │ │ └── comment/ │ │ │ │ │ │ │ └── comment.js │ │ │ │ │ │ ├── lib/ │ │ │ │ │ │ │ ├── codemirror.css │ │ │ │ │ │ │ └── codemirror.js │ │ │ │ │ │ ├── mode/ │ │ │ │ │ │ │ └── crystal/ │ │ │ │ │ │ │ └── crystal.js │ │ │ │ │ │ └── theme/ │ │ │ │ │ │ └── neat.css │ │ │ │ │ └── octicons-19.5.0/ │ │ │ │ │ └── octicons.css │ │ │ │ ├── server.cr │ │ │ │ └── views/ │ │ │ │ ├── _about.html │ │ │ │ ├── _index.html │ │ │ │ ├── _settings.html │ │ │ │ ├── _workbook.html.ecr │ │ │ │ └── layout.html.ecr │ │ │ ├── playground.cr │ │ │ ├── print_hierarchy.cr │ │ │ ├── print_types_visitor.cr │ │ │ ├── table_print.cr │ │ │ ├── typed_def_processor.cr │ │ │ └── unreachable.cr │ │ ├── types.cr │ │ ├── util.cr │ │ └── warnings.cr │ ├── crystal.cr │ └── requires.cr ├── complex.cr ├── compress/ │ ├── deflate/ │ │ ├── deflate.cr │ │ ├── reader.cr │ │ └── writer.cr │ ├── gzip/ │ │ ├── gzip.cr │ │ ├── header.cr │ │ ├── reader.cr │ │ └── writer.cr │ ├── zip/ │ │ ├── checksum_reader.cr │ │ ├── checksum_writer.cr │ │ ├── compression_method.cr │ │ ├── file.cr │ │ ├── file_info.cr │ │ ├── reader.cr │ │ ├── writer.cr │ │ └── zip.cr │ └── zlib/ │ ├── reader.cr │ ├── writer.cr │ └── zlib.cr ├── concurrent.cr ├── crypto/ │ ├── bcrypt/ │ │ ├── base64.cr │ │ ├── blowfish.cr │ │ └── password.cr │ ├── bcrypt.cr │ ├── blowfish.cr │ └── subtle.cr ├── crystal/ │ ├── at_exit_handlers.cr │ ├── atomic_semaphore.cr │ ├── compiler_rt/ │ │ ├── divmod128.cr │ │ ├── fixint.cr │ │ ├── float.cr │ │ ├── mul.cr │ │ ├── multi3.cr │ │ ├── pow.cr │ │ └── shift.cr │ ├── compiler_rt.cr │ ├── datum.cr │ ├── digest/ │ │ ├── md5.cr │ │ └── sha1.cr │ ├── dwarf/ │ │ ├── abbrev.cr │ │ ├── info.cr │ │ ├── line_numbers.cr │ │ └── strings.cr │ ├── dwarf.cr │ ├── elf.cr │ ├── event_loop/ │ │ ├── epoll.cr │ │ ├── file_descriptor.cr │ │ ├── iocp/ │ │ │ ├── fiber_event.cr │ │ │ └── timer.cr │ │ ├── iocp.cr │ │ ├── kqueue.cr │ │ ├── libevent/ │ │ │ ├── event.cr │ │ │ └── lib_event2.cr │ │ ├── libevent.cr │ │ ├── lock.cr │ │ ├── polling/ │ │ │ ├── arena.cr │ │ │ ├── event.cr │ │ │ ├── fiber_event.cr │ │ │ ├── poll_descriptor.cr │ │ │ └── waiters.cr │ │ ├── polling.cr │ │ ├── socket.cr │ │ ├── timers.cr │ │ └── wasi.cr │ ├── event_loop.cr │ ├── fd_lock.cr │ ├── hasher.cr │ ├── iconv.cr │ ├── interpreter.cr │ ├── lib_iconv.cr │ ├── mach_o.cr │ ├── main.cr │ ├── once.cr │ ├── pe.cr │ ├── pointer_linked_list.cr │ ├── pointer_pairing_heap.cr │ ├── print_buffered.cr │ ├── rw_lock.cr │ ├── scheduler.cr │ ├── small_deque.cr │ ├── spin_lock.cr │ ├── syntax_highlighter/ │ │ ├── colorize.cr │ │ └── html.cr │ ├── syntax_highlighter.cr │ ├── system/ │ │ ├── addrinfo.cr │ │ ├── dir.cr │ │ ├── env.cr │ │ ├── fiber.cr │ │ ├── file.cr │ │ ├── file_descriptor.cr │ │ ├── file_info.cr │ │ ├── group.cr │ │ ├── mime.cr │ │ ├── panic.cr │ │ ├── path.cr │ │ ├── print_error.cr │ │ ├── process.cr │ │ ├── random.cr │ │ ├── signal.cr │ │ ├── socket.cr │ │ ├── thread.cr │ │ ├── thread_condition_variable.cr │ │ ├── thread_linked_list.cr │ │ ├── thread_mutex.cr │ │ ├── thread_wait_group.cr │ │ ├── time.cr │ │ ├── unix/ │ │ │ ├── addrinfo.cr │ │ │ ├── arc4random.cr │ │ │ ├── dir.cr │ │ │ ├── env.cr │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── fiber.cr │ │ │ ├── file.cr │ │ │ ├── file_descriptor.cr │ │ │ ├── file_info.cr │ │ │ ├── getrandom.cr │ │ │ ├── group.cr │ │ │ ├── hostname.cr │ │ │ ├── kqueue.cr │ │ │ ├── linux_cpucount.cr │ │ │ ├── main.cr │ │ │ ├── mime.cr │ │ │ ├── path.cr │ │ │ ├── process.cr │ │ │ ├── pthread.cr │ │ │ ├── pthread_condition_variable.cr │ │ │ ├── pthread_mutex.cr │ │ │ ├── signal.cr │ │ │ ├── socket.cr │ │ │ ├── spawn.cr │ │ │ ├── syscall.cr │ │ │ ├── sysconf_cpucount.cr │ │ │ ├── sysctl_cpucount.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── urandom.cr │ │ │ └── user.cr │ │ ├── unix.cr │ │ ├── user.cr │ │ ├── wasi/ │ │ │ ├── addrinfo.cr │ │ │ ├── cpucount.cr │ │ │ ├── dir.cr │ │ │ ├── fiber.cr │ │ │ ├── file.cr │ │ │ ├── file_descriptor.cr │ │ │ ├── group.cr │ │ │ ├── hostname.cr │ │ │ ├── lib_wasi.cr │ │ │ ├── main.cr │ │ │ ├── path.cr │ │ │ ├── process.cr │ │ │ ├── random.cr │ │ │ ├── signal.cr │ │ │ ├── socket.cr │ │ │ ├── thread.cr │ │ │ ├── thread_condition_variable.cr │ │ │ ├── thread_mutex.cr │ │ │ ├── user.cr │ │ │ └── wasi.cr │ │ ├── win32/ │ │ │ ├── addrinfo.cr │ │ │ ├── addrinfo_win7.cr │ │ │ ├── cpucount.cr │ │ │ ├── crypto.cr │ │ │ ├── dir.cr │ │ │ ├── env.cr │ │ │ ├── fiber.cr │ │ │ ├── file.cr │ │ │ ├── file_descriptor.cr │ │ │ ├── file_info.cr │ │ │ ├── group.cr │ │ │ ├── hostname.cr │ │ │ ├── iocp.cr │ │ │ ├── library_archive.cr │ │ │ ├── mime.cr │ │ │ ├── path.cr │ │ │ ├── process.cr │ │ │ ├── random.cr │ │ │ ├── signal.cr │ │ │ ├── socket.cr │ │ │ ├── thread.cr │ │ │ ├── thread_condition_variable.cr │ │ │ ├── thread_mutex.cr │ │ │ ├── time.cr │ │ │ ├── user.cr │ │ │ ├── visual_studio.cr │ │ │ ├── waitable_timer.cr │ │ │ ├── windows_registry.cr │ │ │ ├── windows_sdk.cr │ │ │ ├── wmain.cr │ │ │ └── zone_names.cr │ │ └── windows.cr │ ├── system.cr │ ├── thread_local_value.cr │ ├── tracing.cr │ └── value_with_finalizer.cr ├── csv/ │ ├── builder.cr │ ├── error.cr │ ├── lexer/ │ │ ├── io_based.cr │ │ └── string_based.cr │ ├── lexer.cr │ ├── parser.cr │ └── token.cr ├── csv.cr ├── deque.cr ├── digest/ │ ├── adler32.cr │ ├── crc32.cr │ ├── digest.cr │ ├── io_digest.cr │ ├── md5.cr │ ├── sha1.cr │ ├── sha256.cr │ └── sha512.cr ├── digest.cr ├── dir/ │ └── glob.cr ├── dir.cr ├── docs_main.cr ├── docs_pseudo_methods.cr ├── ecr/ │ ├── lexer.cr │ ├── macros.cr │ ├── process.cr │ └── processor.cr ├── ecr.cr ├── empty.cr ├── enum.cr ├── enumerable.cr ├── env.cr ├── errno.cr ├── exception/ │ ├── call_stack/ │ │ ├── dwarf.cr │ │ ├── elf.cr │ │ ├── interpreter.cr │ │ ├── libunwind.cr │ │ ├── mach_o.cr │ │ ├── null.cr │ │ └── stackwalk.cr │ ├── call_stack.cr │ └── lib_unwind.cr ├── exception.cr ├── fiber/ │ ├── context/ │ │ ├── aarch64-generic.cr │ │ ├── aarch64-microsoft.cr │ │ ├── arm.cr │ │ ├── i386.cr │ │ ├── interpreted.cr │ │ ├── wasm32.cr │ │ ├── x86_64-microsoft.cr │ │ └── x86_64-sysv.cr │ ├── context.cr │ ├── execution_context/ │ │ ├── concurrent.cr │ │ ├── global_queue.cr │ │ ├── isolated.cr │ │ ├── monitor.cr │ │ ├── parallel/ │ │ │ └── scheduler.cr │ │ ├── parallel.cr │ │ ├── runnables.cr │ │ ├── scheduler.cr │ │ └── thread_pool.cr │ ├── execution_context.cr │ ├── list.cr │ ├── pointer_linked_list_node.cr │ ├── stack.cr │ └── stack_pool.cr ├── fiber.cr ├── file/ │ ├── error.cr │ ├── info.cr │ ├── match.cr │ ├── preader.cr │ └── tempfile.cr ├── file.cr ├── file_utils.cr ├── float/ │ ├── fast_float/ │ │ ├── ascii_number.cr │ │ ├── bigint.cr │ │ ├── decimal_to_binary.cr │ │ ├── digit_comparison.cr │ │ ├── fast_table.cr │ │ ├── fast_table_slice_literal.cr │ │ ├── float_common.cr │ │ └── parse_number.cr │ ├── fast_float.cr │ ├── printer/ │ │ ├── cached_powers.cr │ │ ├── diy_fp.cr │ │ ├── dragonbox.cr │ │ ├── dragonbox_cache.cr │ │ ├── grisu3.cr │ │ ├── hexfloat.cr │ │ ├── ieee.cr │ │ ├── ryu_printf.cr │ │ └── ryu_printf_table.cr │ └── printer.cr ├── float.cr ├── gc/ │ ├── boehm.cr │ └── none.cr ├── gc.cr ├── hash.cr ├── html/ │ └── entities.cr ├── html.cr ├── http/ │ ├── client/ │ │ └── response.cr │ ├── client.cr │ ├── common.cr │ ├── content.cr │ ├── cookie.cr │ ├── cookies.cr │ ├── formdata/ │ │ ├── builder.cr │ │ ├── parser.cr │ │ └── part.cr │ ├── formdata.cr │ ├── headers.cr │ ├── log.cr │ ├── params.cr │ ├── request.cr │ ├── server/ │ │ ├── context.cr │ │ ├── handler.cr │ │ ├── handlers/ │ │ │ ├── compress_handler.cr │ │ │ ├── error_handler.cr │ │ │ ├── log_handler.cr │ │ │ ├── static_file_handler.cr │ │ │ ├── static_file_handler.html │ │ │ └── websocket_handler.cr │ │ ├── request_processor.cr │ │ └── response.cr │ ├── server.cr │ ├── status.cr │ ├── web_socket/ │ │ ├── close_code.cr │ │ └── protocol.cr │ └── web_socket.cr ├── http.cr ├── humanize.cr ├── indexable/ │ └── mutable.cr ├── indexable.cr ├── ini.cr ├── int.cr ├── intrinsics.cr ├── io/ │ ├── argf.cr │ ├── buffered.cr │ ├── byte_format.cr │ ├── console.cr │ ├── delimited.cr │ ├── encoding.cr │ ├── encoding_stubs.cr │ ├── error.cr │ ├── evented.cr │ ├── file_descriptor.cr │ ├── hexdump.cr │ ├── memory.cr │ ├── multi_writer.cr │ ├── sized.cr │ └── stapled.cr ├── io.cr ├── iterable.cr ├── iterator.cr ├── json/ │ ├── any.cr │ ├── builder.cr │ ├── from_json.cr │ ├── lexer/ │ │ ├── io_based.cr │ │ └── string_based.cr │ ├── lexer.cr │ ├── parser.cr │ ├── pull_parser.cr │ ├── serialization.cr │ ├── to_json.cr │ └── token.cr ├── json.cr ├── kernel.cr ├── levenshtein.cr ├── lib_c/ │ ├── aarch64-darwin/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── aarch64-linux-android/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── ioctl.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── syscall.cr │ │ │ ├── system_properties.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── aarch64-linux-gnu/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── aarch64-linux-musl/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── arm-linux-gnueabihf/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── i386-linux-gnu/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── i386-linux-musl/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── linux/ │ │ └── tls.cr │ ├── wasm32-wasi/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── iconv.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── sched.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── file.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── times.cr │ │ │ └── types.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-darwin/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-dragonfly/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── sysctl.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-freebsd/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── cpuset.cr │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── ktls.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── sysctl.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-linux-gnu/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-linux-musl/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── random.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── uio.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-netbsd/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── sysctl.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-openbsd/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── event.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── sysctl.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ ├── x86_64-solaris/ │ │ └── c/ │ │ ├── arpa/ │ │ │ └── inet.cr │ │ ├── dirent.cr │ │ ├── dlfcn.cr │ │ ├── elf.cr │ │ ├── errno.cr │ │ ├── fcntl.cr │ │ ├── grp.cr │ │ ├── iconv.cr │ │ ├── limits.cr │ │ ├── link.cr │ │ ├── net/ │ │ │ └── if.cr │ │ ├── netdb.cr │ │ ├── netinet/ │ │ │ ├── in.cr │ │ │ └── tcp.cr │ │ ├── pthread.cr │ │ ├── pwd.cr │ │ ├── sched.cr │ │ ├── signal.cr │ │ ├── stdarg.cr │ │ ├── stddef.cr │ │ ├── stdint.cr │ │ ├── stdio.cr │ │ ├── stdlib.cr │ │ ├── string.cr │ │ ├── sys/ │ │ │ ├── epoll.cr │ │ │ ├── eventfd.cr │ │ │ ├── file.cr │ │ │ ├── mman.cr │ │ │ ├── resource.cr │ │ │ ├── select.cr │ │ │ ├── socket.cr │ │ │ ├── stat.cr │ │ │ ├── time.cr │ │ │ ├── timerfd.cr │ │ │ ├── types.cr │ │ │ ├── un.cr │ │ │ └── wait.cr │ │ ├── termios.cr │ │ ├── time.cr │ │ └── unistd.cr │ └── x86_64-windows-msvc/ │ └── c/ │ ├── afunix.cr │ ├── basetsd.cr │ ├── combaseapi.cr │ ├── consoleapi.cr │ ├── consoleapi2.cr │ ├── corecrt.cr │ ├── dbghelp.cr │ ├── debugapi.cr │ ├── delayimp.cr │ ├── direct.cr │ ├── errhandlingapi.cr │ ├── errno.cr │ ├── fcntl.cr │ ├── fileapi.cr │ ├── guiddef.cr │ ├── handleapi.cr │ ├── heapapi.cr │ ├── in6addr.cr │ ├── inaddr.cr │ ├── int_safe.cr │ ├── io.cr │ ├── ioapiset.cr │ ├── jobapi2.cr │ ├── knownfolders.cr │ ├── libloaderapi.cr │ ├── lm.cr │ ├── malloc.cr │ ├── memoryapi.cr │ ├── minwinbase.cr │ ├── mswsock.cr │ ├── netioapi.cr │ ├── ntdef.cr │ ├── ntdll.cr │ ├── ntifs.cr │ ├── ntsecapi.cr │ ├── ntstatus.cr │ ├── process.cr │ ├── processenv.cr │ ├── processthreadsapi.cr │ ├── profileapi.cr │ ├── regapix.cr │ ├── sddl.cr │ ├── sdkddkver.cr │ ├── security.cr │ ├── shlobj_core.cr │ ├── signal.cr │ ├── stdarg.cr │ ├── stddef.cr │ ├── stdint.cr │ ├── stdio.cr │ ├── stdlib.cr │ ├── string.cr │ ├── stringapiset.cr │ ├── synchapi.cr │ ├── sys/ │ │ ├── stat.cr │ │ ├── types.cr │ │ └── utime.cr │ ├── sysinfoapi.cr │ ├── timezoneapi.cr │ ├── tlhelp32.cr │ ├── userenv.cr │ ├── wdm.cr │ ├── win_def.cr │ ├── winbase.cr │ ├── wincrypt.cr │ ├── windows.cr │ ├── winioctl.cr │ ├── winnls.cr │ ├── winnt.cr │ ├── winreg.cr │ ├── winsock2.cr │ ├── winternl.cr │ ├── ws2def.cr │ ├── ws2ipdef.cr │ ├── ws2tcpip.cr │ └── wtypesbase.cr ├── lib_c.cr ├── lib_z/ │ └── lib_z.cr ├── llvm/ │ ├── abi/ │ │ ├── aarch64.cr │ │ ├── arm.cr │ │ ├── avr.cr │ │ ├── wasm32.cr │ │ ├── x86.cr │ │ ├── x86_64.cr │ │ └── x86_win64.cr │ ├── abi.cr │ ├── basic_block.cr │ ├── basic_block_collection.cr │ ├── builder.cr │ ├── context.cr │ ├── di_builder.cr │ ├── enums/ │ │ └── atomic.cr │ ├── enums.cr │ ├── ext/ │ │ ├── find-llvm-config.sh │ │ ├── llvm-versions.txt │ │ └── llvm_ext.cc │ ├── function.cr │ ├── function_collection.cr │ ├── function_pass_manager.cr │ ├── generic_value.cr │ ├── global_collection.cr │ ├── instruction_collection.cr │ ├── jit_compiler.cr │ ├── lib_llvm/ │ │ ├── analysis.cr │ │ ├── bit_reader.cr │ │ ├── bit_writer.cr │ │ ├── config.cr │ │ ├── core.cr │ │ ├── debug_info.cr │ │ ├── error.cr │ │ ├── execution_engine.cr │ │ ├── initialization.cr │ │ ├── ir_reader.cr │ │ ├── lljit.cr │ │ ├── orc.cr │ │ ├── support.cr │ │ ├── target.cr │ │ ├── target_machine.cr │ │ ├── transforms/ │ │ │ ├── pass_builder.cr │ │ │ └── pass_manager_builder.cr │ │ └── types.cr │ ├── lib_llvm.cr │ ├── lib_llvm_ext.cr │ ├── memory_buffer.cr │ ├── module.cr │ ├── module_pass_manager.cr │ ├── operand_bundle_def.cr │ ├── orc/ │ │ ├── jit_dylib.cr │ │ ├── lljit.cr │ │ ├── lljit_builder.cr │ │ ├── thread_safe_context.cr │ │ └── thread_safe_module.cr │ ├── parameter_collection.cr │ ├── pass_builder_options.cr │ ├── pass_manager_builder.cr │ ├── pass_registry.cr │ ├── phi_table.cr │ ├── target.cr │ ├── target_data.cr │ ├── target_machine.cr │ ├── type.cr │ ├── value.cr │ └── value_methods.cr ├── llvm.cr ├── log/ │ ├── backend.cr │ ├── broadcast_backend.cr │ ├── builder.cr │ ├── dispatch.cr │ ├── entry.cr │ ├── format.cr │ ├── io_backend.cr │ ├── json.cr │ ├── log.cr │ ├── main.cr │ ├── memory_backend.cr │ ├── metadata.cr │ ├── setup.cr │ └── spec.cr ├── log.cr ├── macros.cr ├── math/ │ ├── libm.cr │ └── math.cr ├── mime/ │ ├── media_type.cr │ ├── multipart/ │ │ ├── builder.cr │ │ ├── parser.cr │ │ └── state.cr │ └── multipart.cr ├── mime.cr ├── mutex.cr ├── named_tuple.cr ├── nil.cr ├── number.cr ├── oauth/ │ ├── access_token.cr │ ├── authorization_header.cr │ ├── consumer.cr │ ├── error.cr │ ├── oauth.cr │ ├── request_token.cr │ └── signature.cr ├── oauth.cr ├── oauth2/ │ ├── access_token/ │ │ ├── access_token.cr │ │ ├── bearer.cr │ │ └── mac.cr │ ├── auth_scheme.cr │ ├── client.cr │ ├── error.cr │ ├── error_response.cr │ ├── oauth2.cr │ └── session.cr ├── oauth2.cr ├── object/ │ └── properties.cr ├── object.cr ├── openssl/ │ ├── algorithm.cr │ ├── bio.cr │ ├── cipher.cr │ ├── digest.cr │ ├── error.cr │ ├── hmac.cr │ ├── ktls.cr │ ├── lib_crypto.cr │ ├── lib_ssl.cr │ ├── md5.cr │ ├── pkcs5.cr │ ├── sha1.cr │ ├── ssl/ │ │ ├── context.cr │ │ ├── defaults.cr │ │ ├── hostname_validation.cr │ │ ├── server.cr │ │ └── socket.cr │ └── x509/ │ ├── certificate.cr │ ├── extension.cr │ ├── name.cr │ └── x509.cr ├── openssl.cr ├── option_parser.cr ├── path.cr ├── pointer.cr ├── prelude.cr ├── pretty_print.cr ├── primitives.cr ├── proc.cr ├── process/ │ ├── executable_path.cr │ ├── shell.cr │ └── status.cr ├── process.cr ├── raise.cr ├── random/ │ ├── isaac.cr │ ├── pcg32.cr │ └── secure.cr ├── random.cr ├── range/ │ └── bsearch.cr ├── range.cr ├── reference.cr ├── reference_storage.cr ├── regex/ │ ├── engine.cr │ ├── lib_pcre.cr │ ├── lib_pcre2.cr │ ├── match_data.cr │ ├── pcre.cr │ └── pcre2.cr ├── regex.cr ├── semantic_version.cr ├── set.cr ├── signal.cr ├── slice/ │ └── sort.cr ├── slice.cr ├── socket/ │ ├── address.cr │ ├── addrinfo.cr │ ├── common.cr │ ├── ip_socket.cr │ ├── server.cr │ ├── tcp_server.cr │ ├── tcp_socket.cr │ ├── udp_socket.cr │ ├── unix_server.cr │ └── unix_socket.cr ├── socket.cr ├── spec/ │ ├── cli.cr │ ├── context.cr │ ├── dsl.cr │ ├── example/ │ │ └── procsy.cr │ ├── example.cr │ ├── example_group/ │ │ └── procsy.cr │ ├── expectations.cr │ ├── filters.cr │ ├── formatter.cr │ ├── helpers/ │ │ ├── iterate.cr │ │ └── string.cr │ ├── item.cr │ ├── junit_formatter.cr │ ├── methods.cr │ ├── source.cr │ └── tap_formatter.cr ├── spec.cr ├── static_array.cr ├── steppable.cr ├── string/ │ ├── builder.cr │ ├── formatter.cr │ ├── grapheme/ │ │ ├── grapheme.cr │ │ └── properties.cr │ ├── grapheme.cr │ └── utf16.cr ├── string.cr ├── string_pool.cr ├── string_scanner.cr ├── struct.cr ├── symbol.cr ├── sync/ │ ├── condition_variable.cr │ ├── cv.cr │ ├── errors.cr │ ├── exclusive.cr │ ├── lockable.cr │ ├── mu.cr │ ├── mutex.cr │ ├── rw_lock.cr │ ├── shared.cr │ ├── sync.cr │ ├── type.cr │ └── waiter.cr ├── syscall/ │ ├── aarch64-linux.cr │ ├── arm-linux.cr │ ├── i386-linux.cr │ └── x86_64-linux.cr ├── syscall.cr ├── system/ │ ├── group.cr │ └── user.cr ├── system.cr ├── system_error.cr ├── termios.cr ├── time/ │ ├── format/ │ │ ├── custom/ │ │ │ ├── http_date.cr │ │ │ ├── iso_8601.cr │ │ │ ├── rfc_2822.cr │ │ │ ├── rfc_3339.cr │ │ │ └── yaml_date.cr │ │ ├── formatter.cr │ │ ├── parser.cr │ │ └── pattern.cr │ ├── format.cr │ ├── instant.cr │ ├── location/ │ │ └── loader.cr │ ├── location.cr │ ├── span.cr │ └── tz.cr ├── time.cr ├── tuple.cr ├── unicode/ │ ├── data.cr │ └── unicode.cr ├── union.cr ├── uri/ │ ├── encoding.cr │ ├── json.cr │ ├── params/ │ │ ├── from_www_form.cr │ │ ├── serializable.cr │ │ └── to_www_form.cr │ ├── params.cr │ ├── punycode.cr │ ├── uri_parser.cr │ └── yaml.cr ├── uri.cr ├── uuid/ │ ├── json.cr │ └── yaml.cr ├── uuid.cr ├── va_list.cr ├── value.cr ├── wait_group.cr ├── wasi_error.cr ├── weak_ref.cr ├── winerror.cr ├── xml/ │ ├── attribute_type.cr │ ├── attributes.cr │ ├── builder.cr │ ├── document.cr │ ├── error.cr │ ├── html_parser_options.cr │ ├── libxml2.cr │ ├── namespace.cr │ ├── node/ │ │ └── type.cr │ ├── node.cr │ ├── node_set.cr │ ├── parser_options.cr │ ├── reader/ │ │ └── type.cr │ ├── reader.cr │ ├── save_options.cr │ └── xpath_context.cr ├── xml.cr ├── yaml/ │ ├── any.cr │ ├── builder.cr │ ├── enums.cr │ ├── from_yaml.cr │ ├── lib_yaml.cr │ ├── nodes/ │ │ ├── builder.cr │ │ ├── nodes.cr │ │ └── parser.cr │ ├── nodes.cr │ ├── parse_context.cr │ ├── parser.cr │ ├── pull_parser.cr │ ├── schema/ │ │ ├── core/ │ │ │ └── parser.cr │ │ ├── core.cr │ │ └── fail_safe.cr │ ├── serialization.cr │ └── to_yaml.cr └── yaml.cr ================================================ FILE CONTENTS ================================================ ================================================ FILE: .ameba.yml ================================================ # This configuration file was generated by `ameba --gen-config` # on 2025-06-02 13:57:07 UTC using Ameba version 1.7.0-dev. # The point is for the user to remove these configuration records # one by one as the reported problems are removed from the code base. # # For more details on any individual rule, run `ameba --only RuleName`. # Indicators for comment annotations: # # * `Disabled`: The rule is disabled because it does not seem useful for this repo (or in general). # * `BUG`: A bug in ameba prevents using this rule either entirely or for specific files. # * `FIXME`: The rule seems useful, but requires some effort to resolve. That's deferred for later. # * `TODO`: The rule might be useful, but we need to investigate whether we want to use it or not. Version: "1.7.0-dev" # Documentation # ========================= # Disabled: What's the point in alerting about existing TODOs in code? Documentation/DocumentationAdmonition: Enabled: false # Lint # ========================= Lint/DebugCalls: Excluded: # Samples may legitimately use DebugCalls - samples/**/* # Explicit tests - spec/std/pp_spec.cr Lint/DebuggerStatement: Excluded: # Explicit tests - spec/debug/**/* # Disabled: `else nil` can be useful to explicitly show the consequence of the else branch Lint/ElseNil: Enabled: false # Disabled: We have an explicit CI job for testing the formatter (both latest # and head). No reason to run it through ameba. Lint/Formatting: Enabled: false Lint/LiteralInCondition: Excluded: # Samples may legitimately use literals in conditions - samples/**/* Lint/LiteralInInterpolation: Excluded: - spec/std/random_spec.cr # BUG: https://github.com/crystal-ameba/ameba/issues/611 Lint/LiteralsComparison: Excluded: # Explicit tests for case equality on literals - spec/std/{array,char,int,number,regex,string,symbol,tuple,uint}_spec.cr # TODO: Investigate if some `not_nil!` calls can be avoided. Lint/NotNil: Enabled: false # BUG: https://github.com/crystal-ameba/ameba/issues/605 Lint/SpecFocus: Enabled: false Lint/RandZero: Excluded: # Explicit tests - spec/std/random_spec.cr # FIXME: Resolve shadowing. Lint/ShadowingOuterLocalVar: Enabled: false Lint/SpecFilename: Excluded: - spec/compiler/data/**/* - spec/compiler/lexer/lexer_objects/strings.cr - spec/debug/**/* - spec/llvm-ir/**/* - spec/std/float_printer/ryu_printf_test_cases.cr # BUG: https://github.com/crystal-ameba/ameba/issues/612 Lint/TopLevelOperatorDefinition: Enabled: false # Disabled: We have an explicit CI job for `typos`. No reason to run it through # ameba. Lint/Typos: Enabled: false # TODO: Investigate unused arguments. Lint/UnusedArgument: Enabled: false # TODO: Investigate unused block arguments. Lint/UnusedBlockArgument: Enabled: false Lint/UselessAssign: # BUG: https://github.com/crystal-ameba/ameba/issues/447 # This setting is to avoid false positives from the common use of type # declarations in macro arguments. ExcludeTypeDeclarations: true Excluded: - spec/debug/**/* - samples/mt_gc_test.cr # BUG: https://github.com/crystal-ameba/ameba/issues/624 - spec/std/concurrent/select_spec.cr # Generators assign top-level variables to pass to ECR templates - scripts/generate_* # BUG: https://github.com/crystal-ameba/ameba/issues/623 - scripts/github-changelog.cr # Metrics # ========================= # Disabled: Lot's of violations. Complexity is very individual. Metrics/CyclomaticComplexity: Enabled: false # Naming # ========================= # All disabled. There are many violations and some of the rules are questionable. # TODO: Consider enabling some of these rules. Naming/AccessorMethodName: Enabled: false Naming/BinaryOperatorParameterName: Enabled: false Naming/BlockParameterName: Enabled: false # Disabled: All violations follow the spelling of identifiers in upstream # projects, e.g. for lib bindings. Naming/ConstantNames: Enabled: false Naming/MethodNames: Enabled: false Naming/PredicateName: Enabled: false Naming/QueryBoolMethods: Enabled: false Naming/RescuedExceptionsVariableName: Enabled: false Naming/TypeNames: Enabled: false Naming/VariableNames: Enabled: false # Performance # ========================= Performance/AnyInsteadOfEmpty: Excluded: # These specs explicitly test `#any?` implementations - spec/std/bit_array_spec.cr - spec/std/enumerable_spec.cr - spec/std/hash_spec.cr # Style # ========================= # All disabled. There are many violations and some of the rules are questionable. # TODO: Consider enabling some of these rules. Style/HeredocEscape: Enabled: false Style/HeredocIndent: Enabled: false Style/MultilineCurlyBlock: Enabled: false # Disabled: This rule seems too strict when any negation inside a complex condition is # considered a violation. https://github.com/crystal-ameba/ameba/issues/621 Style/NegatedConditionsInUnless: Enabled: false # BUG: https://github.com/crystal-ameba/ameba/issues/614 Style/ParenthesesAroundCondition: Enabled: false Style/PercentLiteralDelimiters: Enabled: false Style/RedundantNext: Enabled: false Style/RedundantReturn: Enabled: false Style/RedundantSelf: Enabled: false Style/VerboseBlock: Enabled: false Style/WhileTrue: Enabled: false ================================================ FILE: .circleci/config.yml ================================================ version: 2.1 parameters: distribution-scripts-repo: description: "Git url https://github.com/crystal-lang/distribution-scripts/" type: string default: "https://github.com/crystal-lang/distribution-scripts.git" distribution-scripts-version: description: "Git ref for version of https://github.com/crystal-lang/distribution-scripts/" type: string default: "4205934e01733848a559a2908a14dcb16be7f38f" previous_crystal_base_url: description: "Prefix for URLs to Crystal bootstrap compiler" type: string default: "https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1" defaults: environment: &env TRAVIS_BRANCH: $CIRCLE_BRANCH TRAVIS_PULL_REQUEST: $CI_PULL_REQUEST || "false" steps: &ci_steps - checkout - run: bin/ci prepare_system - run: echo 'export CURRENT_TAG="$CIRCLE_TAG"' >> $BASH_ENV - run: bin/ci prepare_build - run: command: bin/ci build no_output_timeout: 30m - run: when: always command: | mkdir -p ~/test-results/spec cp .junit/*.xml ~/test-results/spec/ - store_test_results: path: ~/test-results - store_artifacts: path: ~/test-results/spec jobs: test_linux: machine: image: default environment: <<: *env TRAVIS_OS_NAME: linux ARCH: x86_64 ARCH_CMD: linux64 resource_class: large steps: - checkout - run: bin/ci prepare_system - run: echo 'export CURRENT_TAG="$CIRCLE_TAG"' >> $BASH_ENV - run: bin/ci prepare_build - run: command: bin/ci build no_output_timeout: 30m - run: when: always command: | mkdir -p ~/test-results/spec cp .junit/*.xml ~/test-results/spec/ - store_test_results: path: ~/test-results - store_artifacts: path: ~/test-results/spec - persist_to_workspace: root: . paths: - docs test_alpine: machine: image: default environment: <<: *env TRAVIS_OS_NAME: linux ARCH: x86_64-musl ARCH_CMD: linux64 resource_class: large steps: *ci_steps test_darwin: macos: xcode: 16.4.0 environment: <<: *env TRAVIS_OS_NAME: osx LLVM_CONFIG: /usr/local/opt/llvm/bin/llvm-config steps: - restore_cache: keys: - brew-cache-v1 - checkout - run: bin/ci prepare_system - run: echo 'export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/openssl@1.1/lib/pkgconfig"' >> $BASH_ENV - run: echo 'export CURRENT_TAG="$CIRCLE_TAG"' >> $BASH_ENV - run: bin/ci prepare_build - run: command: bin/ci build no_output_timeout: 30m - run: when: always command: | mkdir -p ~/test-results/spec cp .junit/*.xml ~/test-results/spec/ - store_test_results: path: ~/test-results - store_artifacts: path: ~/test-results/spec - save_cache: key: brew-cache-v1 paths: - /usr/local/Homebrew - ~/Library/Caches/Homebrew/downloads test_preview_mt: machine: image: default resource_class: large environment: <<: *env TRAVIS_OS_NAME: linux ARCH: x86_64 ARCH_CMD: linux64 steps: - checkout - run: bin/ci prepare_system - run: echo 'export CURRENT_TAG="$CIRCLE_TAG"' >> $BASH_ENV - run: bin/ci prepare_build - run: bin/ci with_build_env 'make crystal' - run: command: bin/ci with_build_env 'CRYSTAL_WORKERS=4 make std_spec threads=1 FLAGS="-D preview_mt" junit_output=.junit/std_spec.xml' no_output_timeout: 30m - run: when: always command: | mkdir -p ~/test-results/spec cp .junit/*.xml ~/test-results/spec/ - store_test_results: path: ~/test-results - store_artifacts: path: ~/test-results/spec prepare_common: docker: - image: docker:stable-git steps: # checkout specific distribution-scripts version to perform releases and nightly - run: | git clone << pipeline.parameters.distribution-scripts-repo >> ~/distribution-scripts cd ~/distribution-scripts git checkout << pipeline.parameters.distribution-scripts-version >> # persist relevant information for build process - run: | cd ~/distribution-scripts touch build.env echo "export DOCKER_REPOSITORY=crystallang/crystal" >> build.env # What to build echo "export CRYSTAL_SHA1=$CIRCLE_SHA1" >> build.env # Which previous version use echo "export PREVIOUS_CRYSTAL_RELEASE_DARWIN_TARGZ=<< pipeline.parameters.previous_crystal_base_url >>-darwin-universal.tar.gz" >> build.env cat build.env - persist_to_workspace: root: ../ paths: - distribution-scripts # prepare build for tagged releases prepare_tagged: docker: - image: docker:stable-git steps: - attach_workspace: at: /tmp/workspace - run: | cd /tmp/workspace/distribution-scripts # How to brand it echo "export CRYSTAL_VERSION=$CIRCLE_TAG" >> build.env echo "export DOCKER_TAG=$CIRCLE_TAG" >> build.env # Snapcraft configuration echo "export SNAP_GRADE=stable" >> build.env echo "export SNAP_CHANNEL=edge" >> build.env cat build.env - persist_to_workspace: root: /tmp/workspace paths: - distribution-scripts # prepare build for nightly releases prepare_nightly: docker: - image: docker:stable-git steps: - attach_workspace: at: /tmp/workspace - checkout - run: | # We need CRYSTAL_VERSION in prepare_nightly to use src/VERSION so we publish them as x.y.z-dev in apt/rpm # # How to brand it echo "export CRYSTAL_VERSION=$(cat src/VERSION)" >> /tmp/workspace/distribution-scripts/build.env # # TODO: We might want to do that on docker images also to support updates on multiple development versions the same date. - run: | cd /tmp/workspace/distribution-scripts echo "export DOCKER_TAG=nightly" >> build.env # Build from working directory (needed for omnibus and when version does not match branch/tag) echo "export FORCE_GIT_TAGGED=0" >> build.env # Snapcraft configuration echo "export SNAP_GRADE=devel" >> build.env echo "export SNAP_CHANNEL=edge" >> build.env cat build.env - persist_to_workspace: root: /tmp/workspace paths: - distribution-scripts # prepare build for manual triggered releases like ci branches, maintenance releases, etc. prepare_maintenance: docker: - image: docker:stable-git steps: - attach_workspace: at: /tmp/workspace - run: | cd /tmp/workspace/distribution-scripts # The version is based on the branch name. VERSION=$CIRCLE_BRANCH # We need to sanitize it because there are restrictions on some places # where the version is use (Mac pkg names, snap branch). VERSION=${VERSION/release\//} VERSION=${VERSION//_/-} VERSION=${VERSION//\//-}-dev export VERSION echo "export CRYSTAL_VERSION=$VERSION" >> build.env echo "export DOCKER_TAG=$VERSION" >> build.env # Build from working directory (needed for omnibus and when version does not match branch/tag) echo "export FORCE_GIT_TAGGED=0" >> build.env # Snapcraft configuration echo "export SNAP_GRADE=devel" >> build.env echo "export SNAP_CHANNEL=edge/$VERSION" >> build.env cat build.env - persist_to_workspace: root: /tmp/workspace paths: - distribution-scripts dist_linux: parameters: arch: type: string machine: image: default resource_class: << parameters.arch >> steps: - attach_workspace: at: /tmp/workspace - run: no_output_timeout: 20m command: | cd /tmp/workspace/distribution-scripts source build.env export PREVIOUS_CRYSTAL_RELEASE_LINUX64_TARGZ="<< pipeline.parameters.previous_crystal_base_url >>-linux-$(uname -m).tar.gz" cd linux make all64 release=true - store_artifacts: path: /tmp/workspace/distribution-scripts/linux/build destination: build - persist_to_workspace: root: /tmp/workspace/distribution-scripts/linux/ paths: - build dist_darwin: macos: xcode: 16.4.0 shell: /bin/bash --login -eo pipefail steps: - restore_cache: keys: - brew-cache-v1 - run: name: Setup environment command: | brew unlink python@2 || true brew install ruby@3 libffi pkgconfig libtool automake sudo mkdir -p /opt/crystal sudo chown $(whoami) /opt/crystal/ sudo mkdir -p /var/cache sudo chown $(whoami) /var/cache - attach_workspace: at: /tmp/workspace - run: no_output_timeout: 40m command: | cd /tmp/workspace/distribution-scripts source build.env cd omnibus ruby --version gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)" bundle check || bundle install --binstubs cd ../darwin make - store_artifacts: path: /tmp/workspace/distribution-scripts/darwin/build destination: build - persist_to_workspace: root: /tmp/workspace/distribution-scripts/darwin/ paths: - build push_obs_nightly: docker: - image: crystallang/osc steps: - attach_workspace: at: /tmp/workspace - run: command: | cd /tmp/workspace/distribution-scripts source build.env packages/obs-setup.sh packages/obs-push.sh devel:languages:crystal:nightly ${CRYSTAL_VERSION%-*} $(date '+%Y%m%d') $CRYSTAL_SHA1 \ /tmp/workspace/build/crystal-*-linux-x86_64.tar.gz \ /tmp/workspace/build/crystal-*-docs.tar.gz dist_docker: machine: image: default steps: - attach_workspace: at: /tmp/workspace - run: name: Enable buildx for multiarch builds command: docker buildx create --use - run: name: Build and push multiarch images command: | cd /tmp/workspace/distribution-scripts source build.env cd docker docker login -u ${DOCKER_USER} -p ${DOCKER_PASS} make all TARBALLS=/tmp/workspace/build/ VERSION=${CRYSTAL_VERSION} PUSH=1 - run: name: Smoke tests command: | cd /tmp/workspace/distribution-scripts source build.env cd docker make smoke-all VERSION=${CRYSTAL_VERSION} dist_snap: machine: image: "ubuntu-2204:current" environment: SNAPCRAFT_BUILD_ENVIRONMENT: host steps: - attach_workspace: at: /tmp/workspace - run: command: | sudo apt-get update sudo apt-get install -y make snapd sudo snap install snapcraft --classic cd /tmp/workspace/distribution-scripts source build.env cd snapcraft/ sudo -E make ARCH=amd64 CRYSTAL_TARBALL=/tmp/workspace/build/crystal-$CRYSTAL_VERSION-1-linux-x86_64.tar.gz GRADE=$SNAP_GRADE sudo -E make ARCH=arm64 CRYSTAL_TARBALL=/tmp/workspace/build/crystal-$CRYSTAL_VERSION-1-linux-aarch64.tar.gz GRADE=$SNAP_GRADE sudo -E make push CHANNEL=$SNAP_CHANNEL dist_docs: machine: image: default steps: - attach_workspace: at: /tmp/workspace - run: | cd /tmp/workspace/distribution-scripts source build.env cd docs make CRYSTAL_DOCKER_IMAGE=${DOCKER_REPOSITORY}:${DOCKER_TAG}-build - store_artifacts: path: /tmp/workspace/distribution-scripts/docs/build destination: build - persist_to_workspace: root: /tmp/workspace/distribution-scripts/docs/ paths: - build publish_nightly_artifacts: docker: - image: manastech/s3cmd:2.2-alpine environment: <<: *env AWS_ACCESS_KEY_ID: AKIA2EEIIRCJDEDGK6MQ steps: - attach_workspace: at: /tmp/workspace - run: | mkdir -p /tmp/upload cd /tmp/workspace/build cp crystal-*-darwin-universal.tar.gz /tmp/upload/crystal-nightly-darwin-universal.tar.gz cp crystal-*-linux-x86_64.tar.gz /tmp/upload/crystal-nightly-linux-x86_64.tar.gz cp crystal-*-linux-aarch64.tar.gz /tmp/upload/crystal-nightly-linux-aarch64.tar.gz - run: s3cmd put --recursive /tmp/upload/* s3://artifacts.crystal-lang.org/dist/ dist_artifacts: docker: - image: buildpack-deps:xenial steps: - attach_workspace: at: /tmp/workspace - store_artifacts: path: /tmp/workspace/build destination: dist_packages workflows: version: 2 release: jobs: - test_linux: filters: &release branches: only: - /release\/.+/ - /.*\bci\b.*/ tags: only: /.*/ - test_alpine: filters: *release # - test_darwin: # See https://github.com/crystal-lang/crystal/pull/9763 # filters: *release - test_preview_mt: filters: *release - prepare_common: filters: *release - prepare_maintenance: filters: &maintenance branches: only: - /release\/.+/ - /.*\bci\b.*/ requires: - prepare_common - prepare_tagged: filters: &tagged branches: ignore: /.*/ tags: only: /.*/ requires: - prepare_common - dist_linux: matrix: parameters: arch: [large, arm.medium] filters: *release requires: - prepare_maintenance - prepare_tagged - dist_darwin: filters: *release requires: - prepare_maintenance - prepare_tagged - dist_docker: filters: *release requires: - dist_linux - dist_snap: filters: *release requires: - dist_linux - dist_docs: filters: *release requires: - dist_docker - dist_artifacts: filters: *release requires: - dist_linux - dist_darwin - dist_docs nightly_release: triggers: - schedule: cron: "0 0 * * *" filters: branches: only: - master jobs: - test_linux - test_alpine # - test_darwin # See https://github.com/crystal-lang/crystal/pull/9763 - test_preview_mt - prepare_common - prepare_nightly: requires: - prepare_common - dist_linux: matrix: parameters: arch: [large, arm.medium] requires: - prepare_nightly - dist_darwin: requires: - prepare_nightly - push_obs_nightly: requires: - dist_linux - dist_docs - dist_docker: requires: - dist_linux - dist_snap: requires: - dist_linux - dist_docs: requires: - dist_docker - publish_nightly_artifacts: requires: - dist_linux - dist_darwin - dist_artifacts: requires: - dist_linux - dist_darwin - dist_docs ================================================ FILE: .editorconfig ================================================ root = true [*.{cr,ecr}] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true ================================================ FILE: .gitattributes ================================================ ## Sources *.cr text eol=lf ## Sourced-in dependencies lib/** linguist-vendored ## Generated files # produced by scripts/generate_windows_zone_names.cr src/crystal/system/win32/zone_names.cr linguist-generated # produced by scripts/generate_object_properties.cr src/object/properties.cr # produced by scripts/generate_html_entities.cr src/html/entities.cr linguist-generated # produced by scripts/generate_ssl_server_defaults.cr src/openssl/ssl/defaults.cr linguist-generated # produced by scripts/generate_grapheme_properties.cr src/string/grapheme/properties.cr linguist-generated # produced by scripts/generate_unicode_data.cr src/unicode/data.cr linguist-generated # produced by scripts/generate_glob_specs.cr spec/std/file/match-fast-glob_spec.cr # produced by scripts/generate_grapheme_break_specs.cr spec/std/string/grapheme_break_spec.cr linguist-generated # produced by spec/generate_wasm32_spec.sh spec/wasm32_std_spec.cr linguist-generated # devenv .devenv.flake.nix -merge linguist-generated devenv.lock -merge linguist-generated ## Syntax highlighting Makefile.win linguist-language=makefile ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report.md ================================================ --- name: "\U0001F41B Bug Report" about: I want to report a bug. labels: kind:bug type: Bug --- # Bug Report Make sure to review these points before submitting issues - thank you! - Make sure a similar issue does not exist yet: use the search box, search engine and look at [Stack Overflow](https://stackoverflow.com/questions/tagged/crystal-lang). - **Include reproducible code**: we should be able to paste it into an editor, compile and run it and get the same error as you. Otherwise it's impossible for us to reproduce the bug. - Don't **only** use `play.crystal-lang.org` or `carc.in`: code might be lost and the issue will remain incomplete. Write code in the issue itself. - Reduce code, if possible, to the minimum size that reproduces the bug. - If all of the above is impossible due to a large project, create a branch that reproduces the bug and point us to it. - Include Crystal compiler version (`crystal -v`) and OS. If possible, try to see if the bug still reproduces on master. --- Add a :+1: [reaction] to [issues you find important]. [reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/ [issues you find important]: https://github.com/crystal-lang/crystal/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: "\U00002753 Crystal Community Forum" url: https://forum.crystal-lang.org/c/help-support about: Questions about installing, using Crystal and any related issues. - name: "\U0001F4AC Crystal Community Chat" url: https://gitter.im/crystal-lang/crystal about: "Get in touch with the community, ask for help and talk about Crystal. (IRC: #crystal-lang on libera.chat)" ================================================ FILE: .github/ISSUE_TEMPLATE/discussion.md ================================================ --- name: "\U0001F914 Language Improvement Discussion" about: I want to start a new discussion about improving the language. labels: status:discussion --- # Discussion - What aspect of the language would you like to see improved? - What are the reasons? - Include practical examples to illustrate your points. - Optionally add one (or more) proposals to improve the current situation. --- Add a :+1: [reaction] to [issues you find important]. [reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/ [issues you find important]: https://github.com/crystal-lang/crystal/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request.md ================================================ --- name: "\U0001F680 Feature Request" about: I want to propose a new language feature. labels: kind:feature type: Feature --- # Feature Request - Is your feature request related to a problem? Please describe clearly and concisely what is it. - Describe the feature you would like, optionally illustrated by examples, and how it will solve the above problem. - Describe considered alternative solutions, and the reasons why you have not proposed them as a solution here. - Does it break backward compatibility, if yes then what's the migration path? In case this proposal includes a substantial change to the language, we ask you to go through an [RFC process](https://github.com/crystal-lang/rfcs). The best place to start an open discussion about potential changes is the [Crystal forum](https://forum.crystal-lang.org/c/crystal-contrib/6). --- Add a :+1: [reaction] to [issues you find important]. [reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/ [issues you find important]: https://github.com/crystal-lang/crystal/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/pull_request_template.md ================================================ # Pull Request We thank you for helping improve Crystal. In order to ease the reviewing process, we invite you to read the [guidelines](https://github.com/crystal-lang/crystal/blob/master/CONTRIBUTING.md#making-good-pull-requests) and ask you to consider the following points before submitting a PR: 1. We prefer to discuss the underlying issue _prior_ to discussing the code. Therefore, we kindly ask you to refer to an existing issue, or an existing discussion in a public space with members of the Core Team (forum, Gitter, Discord, ...). In few cases, we acknowledge that this might not be necessary, for instance when refactoring code or small bug fixes. In this case, the PR must include the same information an issue would have: a clear explanation of the issue, reproducible code, etc. 2. Focus the PR to the referred issue, and restraint from adding unrelated changes/additions. We do welcome another PR if you fixed another issue. 3. If your change is big, consider breaking it into several smaller PRs. In general, the smaller the change, the quicker we can review it. 4. ⚠️ Please do not amend previous commits and force push to the PR branch. This makes reviews much harder because reference to previous state is hidden. --- Add a :+1: [reaction] to [pull requests you find important]. [reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/ [pull requests you find important]: https://github.com/crystal-lang/crystal/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc ================================================ FILE: .github/actionlint.yaml ================================================ self-hosted-runner: # Labels of self-hosted runner in array of strings. labels: - runs-on - runner=* - family=* - ram=* - windows-11-arm # actionlint doesn't understand this label yet # Configuration variables in array of strings defined in your repository or # organization. `null` means disabling configuration variables check. # Empty array means no configuration variable is allowed. config-variables: null # Configuration for file paths. The keys are glob patterns to match to file # paths relative to the repository root. The values are the configurations for # the file paths. Note that the path separator is always '/'. # The following configurations are available. # # "ignore" is an array of regular expression patterns. Matched error messages # are ignored. This is similar to the "-ignore" command line option. paths: # .github/workflows/**/*.yml: # ignore: [] ================================================ FILE: .github/renovate.json ================================================ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:recommended" ], "separateMajorMinor": false, "packageRules": [ { "matchDatasources": [ "docker" ], "enabled": false }, { "groupName": "GH Actions", "matchManagers": [ "github-actions" ], "schedule": [ "after 5am and before 8am on Wednesday" ] } ], "labels": [ "topic:infrastructure/ci" ] } ================================================ FILE: .github/workflows/aarch64.yml ================================================ name: AArch64 CI on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: aarch64-musl-build: runs-on: [runs-on, runner=2cpu-linux-arm64, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Build Crystal uses: docker://crystallang/crystal:1.13.2-alpine-84codes-build with: args: make crystal - name: Upload Crystal executable uses: actions/upload-artifact@v7 with: name: crystal-aarch64-musl path: | .build/crystal src/llvm/ext/llvm_ext.o aarch64-musl-test-stdlib: needs: aarch64-musl-build runs-on: [runs-on, runner=4cpu-linux-arm64, "family=m7g", ram=16, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal-aarch64-musl - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run stdlib specs uses: docker://crystallang/crystal:1.13.2-alpine-84codes-build with: args: make std_spec aarch64-musl-test-compiler: needs: aarch64-musl-build runs-on: [runs-on, runner=4cpu-linux-arm64, "family=m7g", ram=16, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal-aarch64-musl - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run compiler specs uses: docker://crystallang/crystal:1.13.2-alpine-84codes-build with: args: make primitives_spec compiler_spec FLAGS=-Dwithout_ffi aarch64-gnu-build: runs-on: [runs-on, runner=2cpu-linux-arm64, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Build Crystal uses: docker://crystallang/crystal:1.13.2-ubuntu-84codes-build with: args: make crystal - name: Upload Crystal executable uses: actions/upload-artifact@v7 with: name: crystal-aarch64-gnu path: | .build/crystal src/llvm/ext/llvm_ext.o aarch64-gnu-test-stdlib: needs: aarch64-gnu-build runs-on: [runs-on, runner=4cpu-linux-arm64, "family=m7g", ram=16, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal-aarch64-gnu - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run stdlib specs uses: docker://crystallang/crystal:1.13.2-ubuntu-84codes-build with: args: make std_spec aarch64-gnu-test-compiler: needs: aarch64-gnu-build runs-on: [runs-on, runner=4cpu-linux-arm64, "family=m7g", ram=16, "run-id=${{ github.run_id }}"] if: github.repository == 'crystal-lang/crystal' steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal-aarch64-gnu - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run compiler specs uses: docker://crystallang/crystal:1.13.2-ubuntu-84codes-build with: args: make primitives_spec compiler_spec ================================================ FILE: .github/workflows/backport.yml ================================================ # WARNING: # When extending this action, be aware that $GITHUB_TOKEN allows write access to # the GitHub repository. This means that it should not evaluate user input in a # way that allows code injection. name: Backport on: pull_request_target: types: [closed, labeled] branches: [master, release/*] permissions: contents: write # so it can comment pull-requests: write # so it can create pull requests jobs: backport: name: Backport Pull Request if: github.repository_owner == 'crystal-lang' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} token: ${{ secrets.BACKPORT_ACTION_GITHUB_PAT }} persist-credentials: false - name: Create backport PR uses: korthout/backport-action@4aaf0e03a94ff0a619c9a511b61aeb42adea5b02 # v4.2.0 with: github_token: ${{ secrets.BACKPORT_ACTION_GITHUB_PAT }} # Config README: https://github.com/korthout/backport-action#backport-action copy_labels_pattern: '^(breaking-change|security|topic:.*|kind:.*|platform:.*)$' copy_milestone: true pull_description: |- Automated backport of #${pull_number} to `${target_branch}`, triggered by a label. ================================================ FILE: .github/workflows/docs.yml ================================================ name: Docs on: push: branches: - master permissions: {} env: TRAVIS_OS_NAME: linux jobs: deploy_api_docs: if: github.repository_owner == 'crystal-lang' env: ARCH: x86_64 ARCH_CMD: linux64 runs-on: ubuntu-latest steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Build docs run: bin/ci with_build_env 'make crystal docs threads=1' - name: Set revision run: echo "$GITHUB_SHA" > ./docs/revision.txt - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-east-1 - name: Deploy API docs to S3 run: | aws s3 sync ./docs s3://crystal-api/api/master --delete ================================================ FILE: .github/workflows/forward-compatibility.yml ================================================ name: Forward Compatibility on: push: paths: - .github/workflows/forward-compatibility.yml schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: TRAVIS_OS_NAME: linux SPEC_SPLIT_DOTS: 160 jobs: # Test against *each* supported Crystal version for forward compatibility. # # This workflow runs on a nightly schedule on `master`. # It can also be dispatched manually when necessary. # # We run a basic version of this test on every commit which covers only the earliest and latest supported versions in `linux.yml#x86_64-gnu-test`. x86_64-gnu-test-forward_compatibility: env: ARCH: x86_64 ARCH_CMD: linux64 CRYSTAL_BOOTSTRAP_VERSION: ${{ matrix.crystal_bootstrap_version }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.2, 1.12.2, 1.13.3, 1.14.1, 1.15.1, 1.16.3, 1.17.1, 1.18.2] env: [{}] include: # libffi is only available starting from the 1.2.2 build images # pcre2 is only available starting from the 1.7.0 build images - crystal_bootstrap_version: 1.1.1 env: FLAGS: -Dwithout_ffi USE_PCRE1: true - crystal_bootstrap_version: 1.2.2 env: USE_PCRE1: true - crystal_bootstrap_version: 1.3.2 env: USE_PCRE1: true - crystal_bootstrap_version: 1.4.1 env: USE_PCRE1: true - crystal_bootstrap_version: 1.5.1 env: USE_PCRE1: true - crystal_bootstrap_version: 1.6.2 env: USE_PCRE1: true steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Test run: bin/ci build env: ${{ matrix.env }} ================================================ FILE: .github/workflows/interpreter.yml ================================================ name: Interpreter Test on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 jobs: test-interpreter_spec: runs-on: ubuntu-24.04 container: image: crystallang/crystal:1.19.1-build name: "Test Interpreter" steps: - uses: actions/checkout@v6 with: persist-credentials: false - name: Test interpreter_spec run: make interpreter_spec junit_output=.junit/interpreter_spec.xml build-interpreter: runs-on: ubuntu-24.04 container: image: crystallang/crystal:1.19.1-build name: Build interpreter steps: - uses: actions/checkout@v6 with: persist-credentials: false - name: Build compiler run: make interpreter=1 release=1 - name: Upload compiler artifact uses: actions/upload-artifact@v7 with: name: crystal-interpreter path: | .build/crystal test-interpreter-std_spec: needs: build-interpreter runs-on: ubuntu-24.04 container: image: crystallang/crystal:1.19.1-build strategy: fail-fast: false matrix: part: [0, 1, 2, 3] name: "Test std_spec with interpreter (${{ matrix.part }})" steps: - uses: actions/checkout@v6 with: persist-credentials: false - name: Download compiler artifact uses: actions/download-artifact@v8 with: name: crystal-interpreter path: .build/ - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run std_spec with interpreter run: SPEC_SPLIT="${{ matrix.part }}%4" bin/crystal i spec/std_spec.cr -- --junit_output .junit/interpreter-std_spec.${{ matrix.part }}.xml test-interpreter-primitives_spec: needs: build-interpreter runs-on: ubuntu-24.04 container: image: crystallang/crystal:1.19.1-build name: "Test primitives_spec with interpreter" steps: - uses: actions/checkout@v6 with: persist-credentials: false - name: Download compiler artifact uses: actions/download-artifact@v8 with: name: crystal-interpreter path: .build/ - name: Mark downloaded compiler as executable run: chmod +x .build/crystal - name: Run primitives_spec with interpreter run: bin/crystal i spec/primitives_spec.cr -- --junit_output .junit/interpreter-primitives_spec.xml ================================================ FILE: .github/workflows/lint.yml ================================================ name: Lint on: push: pull_request: workflow_dispatch: permissions: {} jobs: prek: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false fetch-depth: 0 - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31 with: nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/e99215c1a21cab2a995a3d01fe20d5714addea27.tar.gz # nixpkgs-unstable@2026-03-06 (with devenv 2.0) - uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 with: name: devenv - name: Install devenv.sh run: nix profile install nixpkgs#devenv - name: "Download target branch: ${{ github.base_ref || 'master' }}" run: git fetch origin "${TARGET_BRANCH}" - name: Check whether to run full test on all files id: test_full_run if: ${{ github.event_name != 'workflow_dispatch' }} run: | # Trigger full run if devenv.lock or this workflow file changed if git diff --quiet "origin/${TARGET_BRANCH}" HEAD -- devenv.lock .github/workflows/lint.yml; then echo "test_full_run=false" >> "$GITHUB_OUTPUT" else echo "test_full_run=true" >> "$GITHUB_OUTPUT" fi - name: Run prek on all files id: run_full run: prek run --all-files shell: devenv --profile lint shell bash -- -e {0} if: ${{ github.event_name == 'workflow_dispatch' || steps.test_full_run.outputs.test_full_run == 'true' }} - name: Run prek hooks for changes against target branch (${{ github.base_ref || 'master' }}) run: prek run --from-ref "origin/${TARGET_BRANCH}" --to-ref HEAD shell: devenv --profile lint shell bash -- -e {0} if: "${{ steps.run_full.outcome == 'skipped' }}" env: TARGET_BRANCH: "${{ github.base_ref || 'master' }}" ================================================ FILE: .github/workflows/linux.yml ================================================ name: Linux CI on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: TRAVIS_OS_NAME: linux SPEC_SPLIT_DOTS: 160 jobs: # Test against latest release and the earliest supported Crystal version for forward compatibility. # # A more advanced test which runs against *each* supported version is available in `forward-compatibility.yml` and # runs regularly on a nightly schedule. test: env: ARCH: ${{ matrix.arch }} ARCH_CMD: linux64 runs-on: ${{ case(startsWith(matrix.arch, 'aarch64'), 'ubuntu-24.04-arm', 'ubuntu-latest') }} strategy: fail-fast: false matrix: arch: - x86_64 - x86_64-musl - aarch64 - aarch64-musl env: [{}] include: - arch: x86_64 env: CRYSTAL_BOOTSTRAP_VERSION: 1.0.0 # libffi is only available starting from the 1.2.2 build images FLAGS: "-Dwithout_ffi" # pcre2 is only available starting from the 1.7.0 build images USE_PCRE1: true steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Test run: bin/ci build env: ${{ matrix.env }} test-std: env: ARCH: ${{ matrix.arch }} ARCH_CMD: linux64 runs-on: ${{ case(startsWith(matrix.arch, 'aarch64'), 'ubuntu-24.04-arm', 'ubuntu-latest') }} strategy: fail-fast: false matrix: arch: - x86_64 - aarch64 opts: - flags: "-Dexecution_context -Dpreview_mt" # execution_context: concurrent workers: 1 - flags: "-Dexecution_context -Dpreview_mt" # execution_context: parallel workers: 4 include: - arch: x86_64 opts: flags: "-Devloop=libevent" steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: | bin/ci prepare_build bin/ci with_build_env crystal version - name: Test run: bin/ci with_build_env 'CRYSTAL_WORKERS=${{ matrix.opts.workers || 1 }} make std_spec threads=1 FLAGS="${{ matrix.opts.flags }}"' check_format: env: ARCH: x86_64 ARCH_CMD: linux64 runs-on: ubuntu-latest steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Check Format run: bin/ci format lint_spellcheck: name: Spell Check with Typos runs-on: ubuntu-latest steps: - name: Checkout Actions Repository uses: actions/checkout@v6 with: persist-credentials: false - name: Spell Check Repo uses: crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0 env: CLICOLOR: 1 lint_ameba: runs-on: ubuntu-latest container: ghcr.io/crystal-ameba/ameba:sha-d861f4ed0f904e0ecdad11c26f98e968f7d95afa # 1.7.0-dev steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - run: ameba ================================================ FILE: .github/workflows/llvm.yml ================================================ name: LLVM CI on: push: paths: - 'src/compiler/crystal/codegen/**' - 'src/llvm/**' - 'spec/std/llvm/**' - 'spec/llvm-ir/**' - 'spec/compiler/codegen/**' - '.github/workflows/llvm.yml' pull_request: paths: - 'src/compiler/crystal/codegen/**' - 'src/llvm/**' - 'spec/std/llvm/**' - 'spec/llvm-ir/**' - 'spec/compiler/codegen/**' - '.github/workflows/llvm.yml' schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 jobs: llvm_test: runs-on: ${{ matrix.runs-on }} strategy: fail-fast: false matrix: include: - {llvm_version: 13, runs-on: ubuntu-22.04, codename: jammy} - {llvm_version: 14, runs-on: ubuntu-22.04, codename: jammy} - {llvm_version: 15, runs-on: ubuntu-22.04, codename: jammy} - {llvm_version: 16, runs-on: ubuntu-22.04, codename: jammy} - {llvm_version: 17, runs-on: ubuntu-24.04, codename: noble} - {llvm_version: 18, runs-on: ubuntu-24.04, codename: noble} - {llvm_version: 19, runs-on: ubuntu-24.04, codename: noble} - {llvm_version: 20, runs-on: ubuntu-24.04, codename: noble} - {llvm_version: 21, runs-on: ubuntu-24.04, codename: noble} - {llvm_version: 22, runs-on: ubuntu-24.04, codename: noble} - {runs-on: ubuntu-24.04, codename: noble} name: "LLVM ${{ matrix.llvm_version || 'Nightly' }}" steps: - name: Checkout Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Install LLVM ${{ matrix.llvm_version || 'Nightly' }} run: | sudo apt remove 'llvm-*' 'libllvm*' wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc sudo apt-add-repository -y \ deb \ http://apt.llvm.org/${{ matrix.codename }}/ \ llvm-toolchain-${{ matrix.codename }}${{ matrix.llvm_version && format('-{0}', matrix.llvm_version) || '' }} \ main sudo apt install -y llvm${{ matrix.llvm_version && format('-{0}', matrix.llvm_version) || '' }}-dev lld - name: Install Crystal uses: crystal-lang/install-crystal@v1 with: crystal: "1.19.1" - name: Build libllvm_ext run: make -B deps - name: Test compiler_spec run: make compiler_spec junit_output=.junit/compiler_spec.xml - name: Integration test run: make crystal std_spec threads=1 junit_output=.junit/std_spec.xml ================================================ FILE: .github/workflows/macos.yml ================================================ name: macOS CI on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 CI_NIX_SHELL: true jobs: darwin-test: runs-on: ${{ matrix.runs-on }} name: "${{ matrix.runs-on }} (${{ matrix.arch }})" strategy: fail-fast: false matrix: include: - runs-on: macos-15-intel arch: x86_64-darwin - runs-on: macos-14 arch: aarch64-darwin - runs-on: macos-15 arch: aarch64-darwin steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31 with: extra_nix_config: | experimental-features = nix-command - uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 with: name: crystal-ci signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Test run: bin/ci build - name: Test interpreter run: bin/ci with_build_env 'make interpreter_spec' test-std: runs-on: macos-15 strategy: fail-fast: false matrix: opts: - flags: "-Dexecution_context -Dpreview_mt" # execution_context: concurrent workers: 1 - flags: "-Dexecution_context -Dpreview_mt" # execution_context: parallel workers: 4 steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31 with: extra_nix_config: | experimental-features = nix-command - uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 with: name: crystal-ci signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' - name: Prepare System run: bin/ci prepare_system - name: Prepare Build run: bin/ci prepare_build - name: Test run: bin/ci with_build_env 'CRYSTAL_WORKERS=${{ matrix.opts.workers || 1 }} make std_spec threads=1 FLAGS="${{ matrix.opts.flags }}"' ================================================ FILE: .github/workflows/mingw-w64-steps.yml ================================================ name: MinGW-w64 CI / Build on: workflow_call: inputs: arch: required: true type: string runs-on: required: true type: string msystem: required: true type: string mingw-package-prefix: required: true type: string permissions: {} jobs: build: runs-on: ${{ inputs.runs-on }} steps: - name: Setup MSYS2 id: msys2 uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 with: msystem: ${{ inputs.msystem }} update: true install: >- git make ${{ inputs.mingw-package-prefix }}-pkgconf ${{ inputs.mingw-package-prefix }}-llvm ${{ inputs.mingw-package-prefix }}-crystal - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Build Crystal shell: msys2 {0} run: make crystal interpreter=1 release=1 - name: Package Crystal shell: msys2 {0} run: make install install_dlls deref_symlinks=1 PREFIX="$(pwd)/crystal" - name: Download shards release uses: actions/checkout@v6 with: repository: crystal-lang/shards ref: v0.20.0 path: shards persist-credentials: false - name: Build shards release shell: msys2 {0} working-directory: ./shards run: make CRYSTAL=$(pwd)/../crystal/bin/crystal SHARDS=false release=1 - name: Package Shards shell: msys2 {0} working-directory: ./shards run: | make install PREFIX="$(pwd)/../crystal" SHARDS=false # FIXME: remove after crystal-lang/shards#668 ldd bin/shards.exe | grep -iv ' => /c/windows/system32' | sed 's/.* => //; s/ (.*//' | xargs -t -i /usr/bin/install -m 0755 '{}' "$(pwd)/../crystal/bin/" - name: Upload Crystal executable uses: actions/upload-artifact@v7 with: name: ${{ inputs.arch }}-mingw-w64-crystal path: crystal test-stdlib: runs-on: ${{ inputs.runs-on }} steps: - name: Setup MSYS2 id: msys2 uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 with: msystem: ${{ inputs.msystem }} update: true install: >- git make ${{ inputs.mingw-package-prefix }}-pkgconf ${{ inputs.mingw-package-prefix }}-llvm ${{ inputs.mingw-package-prefix }}-crystal - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Run stdlib specs shell: msys2 {0} run: | export CRYSTAL_SPEC_COMPILER_BIN="$(which crystal.exe)" make std_spec test-compiler: runs-on: ${{ inputs.runs-on }} needs: [build] steps: - name: Setup MSYS2 id: msys2 uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 with: msystem: ${{ inputs.msystem }} update: true install: >- git make ${{ inputs.mingw-package-prefix }}-pkgconf ${{ inputs.mingw-package-prefix }}-llvm ${{ inputs.mingw-package-prefix }}-crystal - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: ${{ inputs.arch }}-mingw-w64-crystal path: crystal - name: Copy compiler build into place run: mkdir .build/ && cp crystal/bin/crystal.exe .build/ - name: Run compiler specs shell: msys2 {0} run: | export CRYSTAL_SPEC_COMPILER_BIN="$(which crystal.exe)" make compiler_spec - name: Run interpreter specs shell: msys2 {0} run: | export CRYSTAL_SPEC_COMPILER_BIN="$(which crystal.exe)" make interpreter_spec - name: Run primitives specs shell: msys2 {0} run: | export CRYSTAL_SPEC_COMPILER_BIN="$(which crystal.exe)" make -o .build/crystal.exe primitives_spec # we know the compiler is fresh; do not rebuild it here env: SPEC_FLAGS: --tag=~external_commands # skip exec_external_command spec because it doesn't work with this setup ================================================ FILE: .github/workflows/mingw-w64.yml ================================================ name: MinGW-w64 CI on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 jobs: x86_64-mingw-w64: name: UCRT64 uses: ./.github/workflows/mingw-w64-steps.yml with: arch: x86_64 runs-on: windows-2025 msystem: UCRT64 mingw-package-prefix: mingw-w64-ucrt-x86_64 aarch64-mingw-w64: name: CLANGARM64 uses: ./.github/workflows/mingw-w64-steps.yml with: arch: aarch64 runs-on: windows-11-arm msystem: CLANGARM64 mingw-package-prefix: mingw-w64-clang-aarch64 ================================================ FILE: .github/workflows/openssl.yml ================================================ name: OpenSSL CI on: push: paths: - 'src/openssl/**' - 'spec/std/digest/**' - 'spec/std/openssl/**' - '.github/workflows/openssl.yml' pull_request: paths: - 'src/openssl/**' - 'spec/std/digest/**' - 'spec/std/openssl/**' - '.github/workflows/openssl.yml' schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: libssl_test: runs-on: ubuntu-latest name: "${{ matrix.pkg }}" container: crystallang/crystal:1.19.1-alpine strategy: fail-fast: false matrix: include: - pkg: "openssl1.1-compat-dev=~1.1.1" repository: http://dl-cdn.alpinelinux.org/alpine/v3.18/community - pkg: "openssl-dev=~3.0" repository: http://dl-cdn.alpinelinux.org/alpine/v3.17/main - pkg: "openssl-dev=~3.3" repository: http://dl-cdn.alpinelinux.org/alpine/v3.20/main - pkg: "openssl-dev" repository: http://dl-cdn.alpinelinux.org/alpine/edge/main - pkg: "libressl-dev=~3.4" repository: http://dl-cdn.alpinelinux.org/alpine/v3.15/community - pkg: "libressl-dev=~3.5" repository: http://dl-cdn.alpinelinux.org/alpine/v3.16/community - pkg: "libressl-dev=~3.8" repository: http://dl-cdn.alpinelinux.org/alpine/v3.20/community - pkg: "libressl-dev" repository: http://dl-cdn.alpinelinux.org/alpine/edge/community steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Uninstall openssl and conflicts run: apk del openssl-dev openssl-libs-static libxml2-static - name: Install ${{ matrix.pkg }} run: apk add "${{ matrix.pkg }}" --repository=${{ matrix.repository }} - name: Print LibSSL version run: bin/crystal eval 'require "openssl"; p! LibSSL::OPENSSL_VERSION, LibSSL::LIBRESSL_VERSION' - name: Run OpenSSL specs run: bin/crystal spec --order=random spec/std/openssl/ ================================================ FILE: .github/workflows/regex-engine.yml ================================================ name: Regex Engine CI on: push: paths: - 'src/regex.cr' - 'src/regex/**' - 'spec/std/regex_spec.cr' - 'spec/std/regex/**' - '.github/workflows/regex-engine.yml' pull_request: paths: - 'src/regex.cr' - 'src/regex/**' - 'spec/std/regex_spec.cr' - 'spec/std/regex/**' - '.github/workflows/regex-engine.yml' schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: pcre: runs-on: ubuntu-latest name: "PCRE" container: crystallang/crystal:1.19.1-alpine steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Remove PCRE2 run: apk del pcre2-dev - name: Assert using PCRE run: bin/crystal eval 'abort unless Regex::Engine == Regex::PCRE' - name: Show PCRE config run: bin/crystal scripts/print_regex_config.cr - name: Run Regex specs run: bin/crystal spec --order=random spec/std/regex* pcre2: runs-on: ubuntu-latest name: "PCRE2" container: crystallang/crystal:1.19.1-alpine steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Assert using PCRE2 run: bin/crystal eval 'abort unless Regex::Engine == Regex::PCRE2' - name: Assert select PCRE run: bin/crystal eval -Duse_pcre 'abort unless Regex::Engine == Regex::PCRE' - name: Show PCRE2 config run: bin/crystal scripts/print_regex_config.cr - name: Run Regex specs run: bin/crystal spec --order=random spec/std/regex* ================================================ FILE: .github/workflows/smoke.yml ================================================ # These jobs are smoke tests for platforms where we don't run full tests. # They ensure that std_spec, compiler_spec and the compiler itself at least # compile for the target with --cross-compile. But the binaries are not linked # and executed. So this does not validate correct behaviour. # # The list of supported platforms is extracted from the lib_c bindings: # # ```terminal-session # $ find src/lib_c -maxdepth 1 -mindepth 1 -type d -printf '%P\n' | sort # aarch64-android # aarch64-darwin # aarch64-linux-gnu # aarch64-linux-musl # arm-linux-gnueabihf # i386-linux-gnu # i386-linux-musl # wasm32-wasi # x86_64-darwin # x86_64-dragonfly # x86_64-freebsd # x86_64-linux-gnu # x86_64-linux-musl # x86_64-netbsd # x86_64-openbsd # x86_64-solaris # x86_64-windows-msvc # ``` # # Platforms for which we currently run full tests are excluded from this workflow. name: Smoke tests on: push: paths: - 'src/lib_c/**' - 'src/crystal/system/**' - '.github/workflows/smoke.yml' pull_request: paths: - 'src/lib_c/**' - 'src/crystal/system/**' - '.github/workflows/smoke.yml' schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: TRAVIS_OS_NAME: linux ARCH: x86_64 ARCH_CMD: linux64 jobs: smoke-test: name: ${{ matrix.target }} runs-on: ubuntu-latest strategy: fail-fast: false max-parallel: 2 matrix: target: - aarch64-linux-android - arm-linux-gnueabihf - i386-linux-gnu - i386-linux-musl - x86_64-dragonfly - x86_64-freebsd - x86_64-netbsd - x86_64-openbsd - x86_64-solaris steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Build fresh compiler run: bin/ci with_build_env make - name: Run smoke test run: bin/ci with_build_env make simple_smoke_test target=${{ matrix.target }} ================================================ FILE: .github/workflows/update-devenv.yml ================================================ name: Update devenv on: schedule: - cron: "0 3 * * 2" # Weekly on Tuesdays push: branches: - master paths: - '.github/workflows/update-devenv.yml' workflow_dispatch: permissions: contents: write pull-requests: write jobs: update-devenv: if: github.repository == 'crystal-lang/crystal' runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: master persist-credentials: false - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31 - uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 with: name: devenv - name: Install devenv.sh run: nix profile add nixpkgs#devenv - name: Update devenv.lock run: devenv update - name: Check for changes id: changes run: | git add devenv.lock if git diff --cached --quiet; then echo "changed=false" >>"$GITHUB_OUTPUT" else echo "changed=true" >>"$GITHUB_OUTPUT" fi - name: Create PR if: steps.changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8 with: commit-message: "Update `devenv.lock`" title: "Update `devenv.lock`" body: "" labels: "topic:infrastructure" branch: infra/update-devenv delete-branch: true ================================================ FILE: .github/workflows/wasm32.yml ================================================ name: WebAssembly CI on: [push, pull_request] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 jobs: wasm32-test: runs-on: ubuntu-24.04 container: crystallang/crystal:1.19.1-build steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Install wasmtime uses: mwilliamson/setup-wasmtime-action@bf814d7d8fc3c3a77dfe114bd9fb8a2c575f6ad6 #v2 with: wasmtime-version: "2.0.0" - name: Install LLVM run: | apt-get update apt-get remove -y 'llvm-*' 'libllvm*' apt-get install -y curl software-properties-common wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc apt-add-repository -y deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main apt-get install -y llvm-18-dev lld-18 ln -s "$(which wasm-ld-18)" /usr/bin/wasm-ld - name: Download wasm32 libs run: | mkdir wasm32-wasi-libs curl -LO https://github.com/lbguilherme/wasm-libs/releases/download/0.0.3/wasm32-wasi-libs.tar.gz echo "cd36f319f8f9f9cd08f723d10e6ec2b92f2e44d3ce3b20344b8041386d85c261 wasm32-wasi-libs.tar.gz" | sha256sum -c - tar -f wasm32-wasi-libs.tar.gz -C wasm32-wasi-libs -xz rm wasm32-wasi-libs.tar.gz - name: Build spec/wasm32_std_spec.cr run: bin/crystal build spec/wasm32_std_spec.cr -o wasm32_std_spec.wasm --target wasm32-wasi -Dwithout_iconv -Dwithout_openssl env: CRYSTAL_LIBRARY_PATH: ${{ github.workspace }}/wasm32-wasi-libs - name: Run wasm32_std_spec.wasm run: | wasmtime run wasm32_std_spec.wasm ================================================ FILE: .github/workflows/win.yml ================================================ name: Windows CI on: [push, pull_request, workflow_dispatch] permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: SPEC_SPLIT_DOTS: 160 CI_LLVM_VERSION: "20.1.7" CI_LLVM_TARGETS: "X86,AArch64" CI_LLVM_LDFLAGS: "psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib ws2_32.lib ntdll.lib" jobs: x86_64-windows-libs: runs-on: windows-2025 steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Cache libraries id: cache-libs uses: actions/cache@v5 with: path: | # openssl and llvm take much longer to build so they are cached separately libs/pcre.lib libs/pcre2-8.lib libs/iconv.lib libs/gc.lib libs/ffi.lib libs/z.lib libs/mpir.lib libs/yaml.lib libs/xml2.lib libs/libxml_VERSION key: win-libs-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc - name: Set up Cygwin if: steps.cache-libs.outputs.cache-hit != 'true' uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6 with: packages: make install-dir: C:\cygwin64 add-to-path: false - name: Build libgc if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-gc.ps1 -BuildTree deps\gc -Version 8.2.8 -AtomicOpsVersion 7.8.2 - name: Build libpcre if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-pcre.ps1 -BuildTree deps\pcre -Version 8.45 - name: Build libpcre2 if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-pcre2.ps1 -BuildTree deps\pcre2 -Version 10.45 - name: Build libiconv if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv -Version 1.18 - name: Build libffi if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-ffi.ps1 -BuildTree deps\ffi -Version 3.5.1 - name: Build zlib if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-z.ps1 -BuildTree deps\z -Version 1.3.1 - name: Build mpir if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-mpir.ps1 -BuildTree deps\mpir - name: Build libyaml if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-yaml.ps1 -BuildTree deps\yaml -Version 0.2.5 - name: Build libxml2 if: steps.cache-libs.outputs.cache-hit != 'true' run: .\etc\win-ci\build-xml2.ps1 -BuildTree deps\xml2 -Version 2.13.8 - name: Cache OpenSSL id: cache-openssl uses: actions/cache@v5 with: path: | libs/crypto.lib libs/ssl.lib libs/openssl_VERSION key: win-openssl-libs-3.4.1-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc - name: Set up NASM if: steps.cache-openssl.outputs.cache-hit != 'true' uses: ilammy/setup-nasm@72793074d3c8cdda771dba85f6deafe00623038b # v1.5.2 - name: Build OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: .\etc\win-ci\build-openssl.ps1 -BuildTree deps\openssl -Version 3.5.0 x86_64-windows-dlls: runs-on: windows-2025 steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Cache libraries id: cache-dlls uses: actions/cache@v5 with: path: | # openssl and llvm take much longer to build so they are cached separately libs/pcre-dynamic.lib libs/pcre2-8-dynamic.lib libs/iconv-dynamic.lib libs/gc-dynamic.lib libs/ffi-dynamic.lib libs/z-dynamic.lib libs/mpir-dynamic.lib libs/yaml-dynamic.lib libs/xml2-dynamic.lib dlls/pcre.dll dlls/pcre2-8.dll dlls/iconv-2.dll dlls/gc.dll dlls/libffi.dll dlls/zlib1.dll dlls/mpir.dll dlls/yaml.dll dlls/libxml2.dll key: win-dlls-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc - name: Set up Cygwin if: steps.cache-dlls.outputs.cache-hit != 'true' uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6 with: packages: make install-dir: C:\cygwin64 add-to-path: false - name: Build libgc if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-gc.ps1 -BuildTree deps\gc -Version 8.2.8 -AtomicOpsVersion 7.8.2 -Dynamic - name: Build libpcre if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-pcre.ps1 -BuildTree deps\pcre -Version 8.45 -Dynamic - name: Build libpcre2 if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-pcre2.ps1 -BuildTree deps\pcre2 -Version 10.45 -Dynamic - name: Build libiconv if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv -Version 1.18 -Dynamic - name: Build libffi if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-ffi.ps1 -BuildTree deps\ffi -Version 3.4.7 -Dynamic - name: Build zlib if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-z.ps1 -BuildTree deps\z -Version 1.3.1 -Dynamic - name: Build mpir if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-mpir.ps1 -BuildTree deps\mpir -Dynamic - name: Build libyaml if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-yaml.ps1 -BuildTree deps\yaml -Version 0.2.5 -Dynamic - name: Build libxml2 if: steps.cache-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-xml2.ps1 -BuildTree deps\xml2 -Version 2.13.6 -Dynamic - name: Cache OpenSSL id: cache-openssl-dlls uses: actions/cache@v5 with: path: | libs/crypto-dynamic.lib libs/ssl-dynamic.lib dlls/libcrypto-3-x64.dll dlls/libssl-3-x64.dll key: win-openssl-dlls-3.4.1-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc - name: Set up NASM if: steps.cache-openssl-dlls.outputs.cache-hit != 'true' uses: ilammy/setup-nasm@72793074d3c8cdda771dba85f6deafe00623038b # v1.5.2 - name: Build OpenSSL if: steps.cache-openssl-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-openssl.ps1 -BuildTree deps\openssl -Version 3.4.1 -Dynamic x86_64-windows-llvm-dlls: runs-on: windows-2025 steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Cache LLVM id: cache-llvm-dlls uses: actions/cache@v5 with: path: | libs/llvm_VERSION libs/llvm-dynamic.lib dlls/LLVM-C.dll key: llvm-dlls-${{ env.CI_LLVM_VERSION }}-${{ hashFiles('etc/win-ci/build-llvm.ps1') }}-msvc - name: Build LLVM if: steps.cache-llvm-dlls.outputs.cache-hit != 'true' run: .\etc\win-ci\build-llvm.ps1 -BuildTree deps\llvm -Version ${{ env.CI_LLVM_VERSION }} -TargetsToBuild ${{ env.CI_LLVM_TARGETS }} -Dynamic x86_64-windows-release: needs: [x86_64-windows-libs, x86_64-windows-dlls, x86_64-windows-llvm-dlls] uses: ./.github/workflows/win_build_portable.yml with: release: true llvm_version: "20.1.7" llvm_targets: "X86,AArch64" llvm_ldflags: "psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib ws2_32.lib ntdll.lib" x86_64-windows-test: runs-on: windows-2025 needs: [x86_64-windows-release] steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal path: build - name: Set up environment run: | Add-Content $env:GITHUB_PATH "$(pwd)\build" Add-Content $env:GITHUB_ENV "CRYSTAL_SPEC_COMPILER_BIN=$(pwd)\build\crystal.exe" Add-Content $env:GITHUB_ENV "LLVM_VERSION=${{ env.CI_LLVM_VERSION }}" Add-Content $env:GITHUB_ENV "LLVM_TARGETS=${{ env.CI_LLVM_TARGETS }}" Add-Content $env:GITHUB_ENV "LLVM_LDFLAGS=${{ env.CI_LLVM_LDFLAGS }}" - name: Run stdlib specs run: make -f Makefile.win std_spec - name: Run compiler specs run: make -f Makefile.win compiler_spec - name: Run interpreter specs run: make -f Makefile.win interpreter_spec - name: Run primitives specs run: make -f Makefile.win -o .build\crystal.exe primitives_spec # we know the compiler is fresh; do not rebuild it here - name: Build samples run: make -f Makefile.win samples test-std: runs-on: windows-2025 needs: [x86_64-windows-release] strategy: fail-fast: false matrix: opts: - flags: "-Dexecution_context -Dpreview_mt" # execution_context: concurrent workers: 1 - flags: "-Dexecution_context -Dpreview_mt" # execution_context: parallel workers: 4 steps: - name: Disable CRLF line ending substitution run: git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal path: build - name: Set up environment run: | Add-Content $env:GITHUB_PATH "$(pwd)\build" Add-Content $env:GITHUB_ENV "CRYSTAL_SPEC_COMPILER_BIN=$(pwd)\build\crystal.exe" Add-Content $env:GITHUB_ENV "LLVM_VERSION=${{ env.CI_LLVM_VERSION }}" Add-Content $env:GITHUB_ENV "LLVM_TARGETS=${{ env.CI_LLVM_TARGETS }}" Add-Content $env:GITHUB_ENV "LLVM_LDFLAGS=${{ env.CI_LLVM_LDFLAGS }}" - name: Test run: make -f Makefile.win std_spec FLAGS="${{ matrix.opts.flags }}" env: CRYSTAL_WORKERS: ${{ matrix.opts.workers || 1 }} x86_64-windows-test-interpreter: runs-on: windows-2025 needs: [x86_64-windows-release] steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal path: build - name: Set up environment run: | Add-Content $env:GITHUB_PATH "$(pwd)\build" Add-Content $env:GITHUB_ENV "CRYSTAL_SPEC_COMPILER_BIN=$(pwd)\build\crystal.exe" Add-Content $env:GITHUB_ENV "LLVM_VERSION=${{ env.CI_LLVM_VERSION }}" Add-Content $env:GITHUB_ENV "LLVM_TARGETS=${{ env.CI_LLVM_TARGETS }}" Add-Content $env:GITHUB_ENV "LLVM_LDFLAGS=${{ env.CI_LLVM_LDFLAGS }}" - name: Run stdlib specs with interpreter run: bin\crystal i spec\std_spec.cr - name: Run primitives specs with interpreter run: bin\crystal i spec\primitives_spec.cr x86_64-windows-installer: if: github.repository_owner == 'crystal-lang' && (startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/ci/')) runs-on: windows-2025 needs: [x86_64-windows-release] steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Download Crystal executable uses: actions/download-artifact@v8 with: name: crystal path: etc/win-ci/portable - name: Set up Inno Setup run: | Invoke-WebRequest -Uri https://jrsoftware.org/download.php/is.exe -OutFile C:\is.exe C:\is.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART - name: Set up environment run: | Add-Content $env:GITHUB_PATH "$(pwd)\etc\win-ci\portable" Add-Content $env:GITHUB_ENV "LLVM_VERSION=${{ env.CI_LLVM_VERSION }}" Add-Content $env:GITHUB_ENV "LLVM_TARGETS=${{ env.CI_LLVM_TARGETS }}" Add-Content $env:GITHUB_ENV "LLVM_LDFLAGS=${{ env.CI_LLVM_LDFLAGS }}" - name: Build docs run: make -f Makefile.win install_docs prefix=etc\win-ci\portable - name: Build installer working-directory: ./etc/win-ci run: | & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" crystal.iss - name: Upload Crystal installer uses: actions/upload-artifact@v7 with: name: crystal-installer path: etc/win-ci/Output/crystal-setup.exe ================================================ FILE: .github/workflows/win_build_portable.yml ================================================ name: Windows CI / Build Portable Package on: workflow_call: inputs: release: required: true type: boolean llvm_version: required: true type: string llvm_targets: required: true type: string llvm_ldflags: required: true type: string permissions: {} jobs: build: runs-on: windows-2025 steps: - name: Disable CRLF line ending substitution run: | git config --global core.autocrlf false - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: Install Crystal uses: crystal-lang/install-crystal@v1 id: install-crystal with: crystal: "1.19.1" - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Restore libraries uses: actions/cache/restore@v5 with: path: | libs/pcre.lib libs/pcre2-8.lib libs/iconv.lib libs/gc.lib libs/ffi.lib libs/z.lib libs/mpir.lib libs/yaml.lib libs/xml2.lib libs/libxml_VERSION key: win-libs-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc fail-on-cache-miss: true - name: Restore OpenSSL uses: actions/cache/restore@v5 with: path: | libs/crypto.lib libs/ssl.lib libs/openssl_VERSION key: win-openssl-libs-3.4.1-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc fail-on-cache-miss: true - name: Restore DLLs uses: actions/cache/restore@v5 with: path: | libs/pcre-dynamic.lib libs/pcre2-8-dynamic.lib libs/iconv-dynamic.lib libs/gc-dynamic.lib libs/ffi-dynamic.lib libs/z-dynamic.lib libs/mpir-dynamic.lib libs/yaml-dynamic.lib libs/xml2-dynamic.lib dlls/pcre.dll dlls/pcre2-8.dll dlls/iconv-2.dll dlls/gc.dll dlls/libffi.dll dlls/zlib1.dll dlls/mpir.dll dlls/yaml.dll dlls/libxml2.dll key: win-dlls-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc fail-on-cache-miss: true - name: Restore OpenSSL DLLs uses: actions/cache/restore@v5 with: path: | libs/crypto-dynamic.lib libs/ssl-dynamic.lib dlls/libcrypto-3-x64.dll dlls/libssl-3-x64.dll key: win-openssl-dlls-3.4.1-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc fail-on-cache-miss: true - name: Restore LLVM DLLs uses: actions/cache/restore@v5 with: path: | libs/llvm_VERSION libs/llvm-dynamic.lib dlls/LLVM-C.dll key: llvm-dlls-${{ inputs.llvm_version }}-${{ hashFiles('etc/win-ci/build-llvm.ps1') }}-msvc fail-on-cache-miss: true - name: Set up environment run: | Add-Content $env:GITHUB_ENV "CRYSTAL_LIBRARY_PATH=$(pwd)\libs" Add-Content $env:GITHUB_ENV "LLVM_VERSION=$env:INPUTS_LLVM_VERSION" Add-Content $env:GITHUB_ENV "LLVM_TARGETS=$env:INPUTS_LLVM_TARGETS" Add-Content $env:GITHUB_ENV "LLVM_LDFLAGS=$env:INPUTS_LLVM_LDFLAGS" env: INPUTS_LLVM_VERSION: ${{ inputs.llvm_version }} INPUTS_LLVM_TARGETS: ${{ inputs.llvm_targets }} INPUTS_LLVM_LDFLAGS: ${{ inputs.llvm_ldflags }} - name: Build LLVM extensions run: make -f Makefile.win deps - name: Build Crystal run: | bin/crystal.bat env make -f Makefile.win -B ${{ inputs.release && 'release=1' || '' }} interpreter=1 - name: Download shards release uses: actions/checkout@v6 with: repository: crystal-lang/shards ref: v0.20.0 path: shards persist-credentials: false - name: Build shards release working-directory: ./shards run: make -f Makefile.win ${{ inputs.release && 'release=1' || '' }} - name: Gather Crystal binaries run: | make -f Makefile.win install prefix=crystal mkdir crystal/lib cp shards/bin/shards.exe crystal/ cp shards/bin/shards.pdb crystal/ cp libs/* crystal/lib/ cp dlls/* crystal/ cp README.md crystal/ - name: Upload Crystal binaries uses: actions/upload-artifact@v7 with: name: crystal path: crystal ================================================ FILE: .github/workflows/xml.yml ================================================ name: XML CI on: push: paths: - 'spec/std/xml/**' - 'src/xml/**' - '.github/workflows/xml.yml' pull_request: paths: - 'spec/std/xml/**' - 'src/xml/**' - '.github/workflows/xml.yml' schedule: - cron: '0 3 * * *' workflow_dispatch: permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: libssl_test: runs-on: ubuntu-latest name: "${{ matrix.pkg }}" container: crystallang/crystal:1.19.1-alpine strategy: fail-fast: false matrix: include: - pkg: "libxml2-dev=~2.9" repository: http://dl-cdn.alpinelinux.org/alpine/v3.16/main - pkg: "libxml2-dev=~2.12" repository: http://dl-cdn.alpinelinux.org/alpine/v3.20/main - pkg: "libxml2-dev=~2.13" repository: http://dl-cdn.alpinelinux.org/alpine/v3.22/main - pkg: "libxml2-dev" repository: http://dl-cdn.alpinelinux.org/alpine/edge/main steps: - name: Download Crystal source uses: actions/checkout@v6 with: persist-credentials: false - name: Uninstall libxml2 and conflicts run: apk del libxml2-dev - name: Install ${{ matrix.pkg }} run: apk add "${{ matrix.pkg }}" --repository=${{ matrix.repository }} - name: Print LibXML2 version run: bin/crystal eval 'require "xml"; p! XML.libxml2_version' - name: Run XML specs run: bin/crystal spec --order=random spec/std/xml/ ================================================ FILE: .github/zizmor.yml ================================================ rules: dangerous-triggers: ignore: - backport.yml unpinned-uses: config: policies: actions/*: ref-pin crystal-lang/*: ref-pin ================================================ FILE: .gitignore ================================================ # Environment configuration /Makefile.local /Makefile.win.local .env .env.* .envrc .envrc.* # Build artifacts *.o *.ll *.s *.obj *.dwo *.dwarf *.pdb *.exe /.build/ /samples/.build/ /docs/ /man/*.gz # CI /coverage/ /tmp/ /.junit/ # Devenv .devenv* devenv.local.nix devenv.local.yaml # direnv .direnv # pre-commit .pre-commit-config.yaml ================================================ FILE: .mailmap ================================================ Ary Borenszweig Ary Borenszweig Ary Borenszweig Brian J. Cardiff Brian J. Cardiff George Dietrich George Dietrich Gustavo Giráldez Johannes Müller Juan Wajnerman Juan Wajnerman Juan Wajnerman Julien Reichardt Martin Verzilli Matías García Isaía Matías García Isaía Stephanie Hobbs ================================================ FILE: .markdownlint.yaml ================================================ default: true heading-style: "setext" no-inline-html: false line-length: false ol-prefix: style: "ordered" ul-style: style: "dash" ul-indent: indent: 2 no-blanks-blockquote: false emphasis-style: style: "underscore" strong-style: style: "asterisk" no-duplicate-heading: siblings_only: true no-bare-urls: false fenced-code-language: false commands-show-output: false first-line-h1: front_matter_title: "^\\s*(page_)?title\\s*[:=]" exclude: .github/PULL_REQUEST_TEMPLATE/pull_request_template.md no-alt-text: false hard_tab: code_blocks: false ================================================ FILE: .markdownlintignore ================================================ /lib/ ================================================ FILE: .well-known/funding-manifest-urls ================================================ https://crystal-lang.org/funding.json ================================================ FILE: Brewfile ================================================ brew "gmp" brew "libevent" brew "pcre" brew "pkg-config" brew "openssl@1.1" brew "llvm@11", link: true, conflicts_with: ["python@2"] ================================================ FILE: CHANGELOG.md ================================================ # Changelog For information on prior releases, refer to the changelogs in [./doc/changelogs](./doc/changelogs/README.md) ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainers in private or by sending an email to [crystal@manas.tech](mailto:crystal@manas.tech). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Crystal So you've decided to contribute to Crystal. Excellent! ## Using the issue tracker The [issue tracker](https://github.com/crystal-lang/crystal/issues) is the heart of Crystal's work. Use it for bugs, questions, proposals and feature requests. Please always **open a new issue before sending a pull request** if you want to add a new feature to Crystal, unless it is a minor fix, and wait until someone from the core team approves it before you actually start working on it. Otherwise, you risk having the pull request rejected, and the effort implementing it goes to waste. And if you start working on an implementation for an issue, please **let everyone know in the comments** so someone else does not start working on the same thing. Regardless of the kind of issue, please make sure to look for similar existing issues before posting; otherwise, your issue may be flagged as `duplicated` and closed in favour of the original one. Also, once you open a new issue, please make sure to honour the items listed in the issue template. If you open a question, remember to close the issue once you are satisfied with the answer and you think there's no more room for discussion. We'll anyway close the issue after some days. If something is missing from the language it might be that it's not yet implemented or that it was purposely left out. If in doubt, just ask. Substantial changes go through an [RFC process](https://github.com/crystal-lang/rfcs). The best place to start an open discussion about potential changes is the [Crystal forum](https://forum.crystal-lang.org/c/crystal-contrib/6). ### What's needed right now You can find a list of tasks that we consider suitable for a first time contribution with the [good first issue label](https://github.com/crystal-lang/crystal/contribute). As you feel more confident, you can keep an eye out for open issues with the following labels: - [`community:to-research`](https://github.com/crystal-lang/crystal/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Acommunity%3Ato-research): Help needed on **researching and investigating** the issue at hand; could be from going through an RFC to figure out how something _should_ be working, to go through details on a C-library we'd like to bind. - [`community:to-design`](https://github.com/crystal-lang/crystal/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Acommunity%3Ato-design): As an issue has been accepted, we are looking for **ideas on how it could be implemented**, this is, a high-level design for the feature at hand. - [`community:to-implement`](https://github.com/crystal-lang/crystal/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Acommunity%3Ato-implement): After a design has been agreed upon, the remaining task is to actually **code** it and send a PR! - [`community:to-document`](https://github.com/crystal-lang/crystal/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Acommunity%3Ato-document): Similar to the one above, but this one is for those awesome devs that are happy to **contribute with documentation** instead of just code. Furthermore, these are the most important general topics in need right now, so if you are interested open an issue to start working on it: - Documenting the language - Documenting the standard library - Adding missing bits of the standard library, and/or improving its performance ### Labels Issue tracker labels are sorted by category: community, kind, pr, status and topic. #### Community These are the issues where help from the community is most welcome. See above for a description on `newcomer`, `to-research`, `to-design`, `to-implement` and `to-document`. Label `in-progress` is used to signal that someone from the community is already working on the issue (since GitHub does not allow for a non-team member to be _assigned_ to an issue). The label `shard-idea` refers to a feature proposal that, albeit good, is better suited as a separate shard rather than as part of the core library; so if you are looking for a shard of your own to start working on, these issues are good starting points. #### Kind The most basic category is the kind of the issue: `bug`, `feature` and `question` speak for themselves, while `refactor` is left for changes that do not actually introduce a new a feature, and are not fixing something that is broken, but rather clean up the code (or documentation!). #### PR Pull-request only labels, used to signal that a pull request `needs-review` by a core team member, or that is still `wip` (work in progress). #### Topic Topic encompasses the broad aspect of the language that the issue refers to: could be performance, the compiler, the type system, the code formatter, concurrency, and quite a large etc. #### Status Status labels attempt to capture the lifecycle of an issue: - A detailed proposal on a feature is marked as `draft`, while a more general argument is usually labelled as `discussion` until a consensus is achieved. - An issue is `accepted` when it describes a feature or bugfix that a core team member has agreed to have added to the language, so as soon as a design is discussed (if needed), it's safe to start working on a pull request. - Bug reports are marked as `needs-more-info`, where the author is requested to provide the info required; note that the issue may be closed after some time if it is not supplied. - Issues that are batched in an epic to be worked on as a group are typically marked as `deferred`, while low-prio issues or tasks far away in the roadmap are marked as `someday`. - Closed issues are marked as `implemented`, `invalid`, `duplicate` or `wontfix`, depending on their resolution. ## Contributing ### The documentation The language reference is available at . See the repository at [crystal-lang/crystal-book](https://github.com/crystal-lang/crystal-book) for contributing to it. The [standard library documentation](https://crystal-lang.org/api/) is on the code itself, in this repository. The [`master` version](https://crystal-lang.org/api/master/) is updated with every push to the master branch. It uses a subset of [Markdown](http://daringfireball.net/projects/markdown/). You can [use Ruby as a source of inspiration](https://twitter.com/yukihiro_matz/status/549317901002342400) whenever applicable. To generate the docs execute `make docs`. Please follow the guidelines described in our [language documentation](https://crystal-lang.org/reference/conventions/documenting_code.html), like the use of the third person. Additionally, all official documentation can be found on [the Crystal website](https://crystal-lang.org/docs/). ### The standard library 1. [Fork](https://github.com/crystal-lang/crystal/fork) and checkout the repository Once in the cloned directory, and once you [installed Crystal](https://crystal-lang.org/install/), you can execute `bin/crystal` instead of `crystal`. This is a wrapper that will use the cloned repository as the standard library. Otherwise the barebones `crystal` executable uses the standard library that comes in your installation. Next, make changes to the standard library, making sure you also provide corresponding specs. To run the specs for the standard library, run `make std_spec`. To run a particular spec: `bin/crystal spec spec/std/array_spec.cr`. You can use `make help` for a list of available make targets. Note: at this point you might get long compile error that include "library not found for: ...". This means you are [missing some libraries](https://github.com/crystal-lang/crystal/wiki/All-required-libraries). Make sure that your changes follow the recommended [Coding Style](https://crystal-lang.org/reference/conventions/coding_style.html). You can run `crystal tool format` to automate this. Then push your changes and create a pull request. ### The compiler itself If you want to add/change something in the compiler, the first thing you will need to do is to [install the compiler](https://crystal-lang.org/install/). Once you have a compiler up and running, check that executing `crystal` on the command line prints its usage. Now you can setup your environment to compile Crystal itself, which is itself written in Crystal. The compiler needs [LLVM](https://llvm.org) and some other libraries. See [list of all required libraries](https://github.com/crystal-lang/crystal/wiki/All-required-libraries). Executing `make crystal` builds the compiler into `.build/compiler` and you can run it using the wrapper script at `bin/crystal`. The script sets up the proper environment variables that the compiler can find the standard library source files in `src/`. `make compiler_spec` runs the compiler specs. `make std_spec` runs the standard library specs. `make primitives_spec` runs the specs for primitive methods with an up-to-date Crystal compiler. You can use `make help` for a list of available make targets. ## This guide If this guide is not clear and it needs improvements, please send pull requests against it. Thanks! :-) ## Making good pull requests The commit history should consist of commits that transform the codebase from one state into another one, motivated by something that should change, be it a bugfix, a new feature or some ground work to support a new feature, like changing an existing API or introducing a new isolated class that is later used in the same pull request. Review history should be preserved in a pull request. If you need to push a change to an open pull request (for example because specs broke and required a fix, or for applying a review suggestion) these changes should be added as individual fixup commits. Please do not amend previous commits and force push to the PR branch. This makes reviews much harder because reference to previous state is hidden. If changes introduced to `master` branch result in conflicts, it should be merged with a merge commit (`git fetch upstream/master; git merge upstream/master`). ### Minimum requirements 1. Describe reasons and result of the change in the pull request comment. 2. Do not force push to a pull request. The development history should be easily traceable. 3. Any change to a public API requires appropriate documentation: params (and particularly interesting combinations of them if the method is complex), results, interesting, self-contained examples. 4. Any change to behaviour needs to be reflected and validated with specs. 5. Any change affecting the compiler or performance-critical features in the standard library should be checked with benchmarks how it affects performance. ### Reviews Reviews are conducted by community members to validate a contribution and ensure quality standards are met. Approvals from Core Team members are required for accepting a pull requests. Other community members are encouraged to do reviews as well. Leave suggestions for improvements or approve a change when it looks good to you. 1. Make sure the [formal minimum requirements](#minimum-requirements) are met, for the change itself and the PR. Cross check with the referenced issue(s). 2. Check if CI is successful. If not, try to figure out what's wrong and add a comment about it. If a failure seems unrelated, maintainers can try to rerun the job. 3. Leave inline comments when you want to request changes or ask for clarification. Suggestions are often understood as requirements, so make it clear if a proposal is optional or you're just asking for feedback. ### Accepting a Pull Request The process of accepting a pull request entails the following check list: 1. At least two approvals by Core Team members; one approval if the author is a Core Team member. Only approvals based on the most recent code version count (ignoring minor changes like fixing a typo). 2. There are no outstanding questions nor requested changes in the pull request and associated issues. 3. Title and description appropriately represent the final state of the change. 4. Proper labels are applied (usually at least a `topic:` and `kind:` label). 5. Change is based on a fairly recent commit of the `master` branch. When in doubt, merge `master` and wait for CI. 6. CI is green. When these conditions are met, a Core Team member can mark the pull request as accepted by adding it to the current development milestone. This signals that the PR is scheduled to be merged soon and gives another chance for final reviews. The current [development milestone](https://github.com/crystal-lang/crystal/milestones) is typically the milestone for the next release. During the freeze period of a release, feature enhancements are added to the milestone of the next release. Freeze periods are announced on the community forums and usually span two weeks before the scheduled date of a minor release. ### Merge Queue The current [development milestone](https://github.com/crystal-lang/crystal/milestones) serves as a merge queue. Open pull requests on that milestone are eligible for being merged. Pending pull requests should usually stay in the queue for at least one full business day, allowing other reviewers to take a final look at it. This wait time can be extended, for example for big changes or when there was a lot of recent activity in the discussion. Urgent bug and regression fixes can skip the line. If reasonable objection or questions arise while waiting for merge, the pull request must be removed from the milestone until they are resolved. It's good practice to have a single maintainer responsible for operating the merge queue. ### Merging Before merging, make sure the pull request has been on the merge queue for some time (usually 1+ business days) and there has not been any more recent discussion that questions the current state of the change. If conditions are met, the pull request can finally be merged. Use squash merge to not pollute the version history of the main branch with details of the pull request process. For non-trivial changes, the merge commit should contain a short description. ### For maintainers with push access 1. Do not directly commit to the `master` branch. Always create a feature branch and pull request. 2. Feature branches should typically be created in your fork. The main repo should only contain essential branches. - CI changes affecting circle CI only run for branches on the main repo. They should be prefixed `ci/` to trigger a maintenance release. - Long-running feature branches that accept contributions must be pushed to the main repo in order to allow PRs targeting that branch. ## Git pre-commit hook Code submitted to this repository should be formatted according to `crystal tool format`. A pre-commit hook can be installed into the local git repo to ensure the formatter validates every commit: Install the pre-commit hook: ```sh ln -s scripts/git/pre-commit .git/hooks ``` ## Code of Conduct Please note that this project is released with a [Contributor Code of Conduct][ccoc]. By participating in this project you agree to abide by its terms. [ccoc]: https://github.com/crystal-lang/crystal/blob/master/CODE_OF_CONDUCT.md ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---------------------------------------------------------------------------- Runtime Library Exception to the Apache 2.0 License: As an exception, if you use this Software to compile your source code and portions of this Software are embedded into the binary product as a result, you may redistribute such product without providing attribution as would otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. ================================================ FILE: LICENSES/Apache-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: LICENSES/MIT.txt ================================================ MIT License Copyright (c) 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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. ================================================ FILE: LICENSES/Swift-exception.txt ================================================ ### Runtime Library Exception to the Apache 2.0 License: ### As an exception, if you use this Software to compile your source code and portions of this Software are embedded into the binary product as a result, you may redistribute such product without providing attribution as would otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. ================================================ FILE: Makefile ================================================ all: -include Makefile.local # for optional local options e.g. threads # Recipes for this Makefile ## Build the compiler ## $ make ## Build the compiler with progress output ## $ make progress=1 ## Clean up built files then build the compiler ## $ make clean crystal ## Build the compiler in release mode ## $ make crystal release=1 interpreter=1 ## Run tests ## $ make test ## Run stdlib tests ## $ make std_spec ## Run compiler tests ## $ make compiler_spec ## Run generators (Unicode, SSL config, ...) ## $ make -B generate_data CRYSTAL ?= crystal## which previous crystal compiler use release ?= ## Compile in release mode stats ?= ## Enable statistics output progress ?= ## Enable progress output threads ?= ## Maximum number of threads to use debug ?= ## Add symbolic debug info verbose ?= ## Run specs in verbose mode junit_output ?= ## Path to output junit results static ?= ## Enable static linking target ?= ## Cross-compilation target interpreter ?= ## Enable interpreter feature check ?= ## Enable only check when running format order ?=random ## Enable order for spec execution (values: "default" | "random" | seed number) deref_symlinks ?= ## Dereference symbolic links for `make install` docs_sanitizer ?= ## Enable sanitization for documentation generation sequential_codegen ?=$(if $(filter 0,$(supports_preview_mt)),true,)## Enforce sequential codegen in compiler builds. Base compiler before Crystal 1.8 cannot build with `-Dpreview_mt -Dexecution_context` O := .build SOURCES := $(shell find src -name '*.cr') SPEC_SOURCES := $(shell find spec -name '*.cr') MAN1PAGES := $(patsubst doc/man/%.adoc,man/%.1,$(wildcard doc/man/*.adoc)) override FLAGS += -D strict_multi_assign -D preview_overload_order $(if $(release),--release )$(if $(stats),--stats )$(if $(progress),--progress )$(if $(threads),--threads $(threads) )$(if $(debug),-d )$(if $(static),--static )$(if $(LDFLAGS),--link-flags="$(LDFLAGS)" )$(if $(target),--cross-compile --target $(target) ) # NOTE: USE_PCRE1 is only used for testing compatibility with legacy environments that don't provide libpcre2. # Newly built compilers should never be distributed with libpcre to ensure syntax consistency. override COMPILER_FLAGS += $(if $(interpreter),,-Dwithout_interpreter )$(if $(docs_sanitizer),,-Dwithout_libxml2 ) -Dwithout_openssl -Dwithout_zlib$(if $(sequential_codegen),, -Dpreview_mt -Dexecution_context) $(if $(USE_PCRE1),-Duse_pcre,-Duse_pcre2) SPEC_WARNINGS_OFF := --exclude-warnings spec/std --exclude-warnings spec/compiler --exclude-warnings spec/primitives --exclude-warnings src/float/printer --exclude-warnings src/random.cr override SPEC_FLAGS += $(if $(verbose),-v )$(if $(junit_output),--junit_output $(junit_output) )$(if $(order),--order=$(order) ) CRYSTAL_CONFIG_LIBRARY_PATH := '$$ORIGIN/../lib/crystal' ifndef CRYSTAL_CONFIG_BUILD_COMMIT CRYSTAL_CONFIG_BUILD_COMMIT := $(shell git rev-parse --short HEAD 2> /dev/null) endif CRYSTAL_CONFIG_PATH := '$$ORIGIN/../share/crystal/src' ifndef BASE_CRYSTAL_VERSION BASE_CRYSTAL_VERSION := $(shell $(CRYSTAL) env CRYSTAL_VERSION) endif ifndef CRYSTAL_VERSION CRYSTAL_VERSION := $(shell cat src/VERSION) endif ifndef SOURCE_DATE_EPOCH SOURCE_DATE_EPOCH := $(shell (cat src/SOURCE_DATE_EPOCH || (git show -s --format=%ct HEAD || stat -c "%Y" Makefile ||stat -f "%m" Makefile)) 2> /dev/null) endif check_lld := command -v ld.lld >/dev/null && case "$$(uname -s)" in MINGW32*|MINGW64*|Linux) echo 1;; esac ifeq ($(shell $(check_lld)),1) EXPORT_CC ?= CC="$(CC) -fuse-ld=lld" endif override EXPORTS += \ CRYSTAL_CONFIG_BUILD_COMMIT="$(CRYSTAL_CONFIG_BUILD_COMMIT)" \ CRYSTAL_CONFIG_PATH=$(CRYSTAL_CONFIG_PATH) \ SOURCE_DATE_EPOCH="$(SOURCE_DATE_EPOCH)" override EXPORTS_BUILD += \ $(EXPORT_CC) \ CRYSTAL_CONFIG_LIBRARY_PATH=$(CRYSTAL_CONFIG_LIBRARY_PATH) SHELL = sh ifeq ($(LLVM_VERSION),) ifndef LLVM_CONFIG LLVM_CONFIG := $(shell src/llvm/ext/find-llvm-config.sh) endif LLVM_VERSION := $(if $(LLVM_CONFIG),$(shell "$(LLVM_CONFIG)" --version 2> /dev/null)) endif # Crystal versions before 1.8 cannot build a functional compiler with `-Dpreview_mt` (https://github.com/crystal-lang/crystal/pull/16380) supports_preview_mt := $(if $(filter 1.8.0,$(shell printf "%s\n%s" "1.8.0" "$(BASE_CRYSTAL_VERSION)" | sort -V | tail -n1)),0,1) LLVM_EXT_DIR = src/llvm/ext LLVM_EXT_OBJ = $(LLVM_EXT_DIR)/llvm_ext.o CXXFLAGS += $(if $(debug),-g -O0) # MSYS2 support (native Windows should use `Makefile.win` instead) ifeq ($(OS),Windows_NT) EXE := .exe WINDOWS := 1 else EXE := WINDOWS := endif CRYSTAL_BIN := crystal$(EXE) DESTDIR ?= PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin LIBDIR ?= $(PREFIX)/lib DATADIR ?= $(PREFIX)/share DOCDIR ?= $(DATADIR)/doc/crystal MANDIR ?= $(DATADIR)/man INSTALL ?= /usr/bin/install ifeq ($(or $(TERM),$(TERM),dumb),dumb) colorize = $(shell printf "%s" "$1" >&2) else colorize = $(shell printf "\033[33m%s\033[0m\n" "$1" >&2) endif DEPS = $(LLVM_EXT_OBJ) ifneq ($(LLVM_VERSION),) ifeq ($(shell test $(firstword $(subst ., ,$(LLVM_VERSION))) -ge 18; echo $$?),0) DEPS = endif endif check_llvm_config = $(eval \ check_llvm_config := $(if $(LLVM_VERSION),\ $(call colorize,Using $(or $(LLVM_CONFIG),externally configured LLVM) [version=$(LLVM_VERSION)]),\ $(error "Could not locate compatible llvm-config, make sure it is installed and in your PATH, or set LLVM_VERSION / LLVM_CONFIG. Compatible versions: $(shell cat src/llvm/ext/llvm-versions.txt)))\ ) .PHONY: all all: crystal ## Build all files (currently crystal only) [default] .PHONY: test test: spec ## Run tests .PHONY: spec spec: std_spec primitives_spec compiler_spec .PHONY: std_spec std_spec: $(O)/std_spec$(EXE) ## Run standard library specs $(O)/std_spec$(EXE) $(SPEC_FLAGS) .PHONY: compiler_spec compiler_spec: $(O)/compiler_spec$(EXE) ## Run compiler specs $(O)/compiler_spec$(EXE) $(SPEC_FLAGS) .PHONY: primitives_spec primitives_spec: $(O)/primitives_spec$(EXE) ## Run primitives specs $(O)/primitives_spec$(EXE) $(SPEC_FLAGS) .PHONY: interpreter_spec interpreter_spec: $(O)/interpreter_spec$(EXE) ## Run interpreter specs $(O)/interpreter_spec$(EXE) $(SPEC_FLAGS) .PHONY: simple_smoke_test simple_smoke_test: ## Build std specs as a smoke test simple_smoke_test: $(O)/std_spec$(EXE) .PHONY: smoke_test smoke_test: ## Build std specs, compiler specs and compiler as a smoke test smoke_test: $(O)/std_spec$(EXE) $(O)/compiler_spec$(EXE) $(O)/$(CRYSTAL_BIN) SHELLCHECK_SOURCES := $(wildcard **/*.sh) $(wildcard **/*.bash) bin/crystal bin/ci bin/check-compiler-flag scripts/git/pre-commit .PHONY: lint-shellcheck lint-shellcheck: shellcheck --severity=warning $(SHELLCHECK_SOURCES) .PHONY: all_spec all_spec: $(O)/all_spec$(EXE) ## Run all specs (note: this builds a huge program; `test` recipe builds individual binaries and is recommended for reduced resource usage) $(O)/all_spec$(EXE) $(SPEC_FLAGS) .PHONY: samples samples: ## Build example programs $(MAKE) -C samples .PHONY: docs docs: ## Generate standard library documentation $(call check_llvm_config) ./bin/crystal docs src/docs_main.cr $(DOCS_OPTIONS) --project-name=Crystal --project-version=$(CRYSTAL_VERSION) --source-refname=$(CRYSTAL_CONFIG_BUILD_COMMIT) cp -R -P -p doc/ docs/ .PHONY: crystal crystal: $(O)/$(CRYSTAL_BIN) ## Build the compiler .PHONY: deps llvm_ext deps: $(DEPS) ## Build dependencies llvm_ext: $(LLVM_EXT_OBJ) .PHONY: format format: ## Format sources ./bin/crystal tool format$(if $(check), --check) src spec samples scripts .PHONY: generate_data generate_data: ## Run generator scripts for Unicode, SSL config, ... $(MAKE) -B -f scripts/generate_data.mk .PHONY: install install: $(O)/$(CRYSTAL_BIN) man/crystal.1.gz ## Install the compiler at DESTDIR $(INSTALL) -d -m 0755 "$(DESTDIR)$(BINDIR)/" $(INSTALL) -m 0755 "$(O)/$(CRYSTAL_BIN)" "$(DESTDIR)$(BINDIR)/$(CRYSTAL_BIN)" $(INSTALL) -d -m 0755 $(DESTDIR)$(DATADIR)/crystal cp -R -p $(if $(deref_symlinks),-L,-P) src "$(DESTDIR)$(DATADIR)/crystal/src" rm -rf "$(DESTDIR)$(DATADIR)/crystal/$(LLVM_EXT_OBJ)" # Don't install llvm_ext.o $(INSTALL) -d -m 0755 "$(DESTDIR)$(MANDIR)/man1/" $(INSTALL) -m 644 man/crystal.1.gz "$(DESTDIR)$(MANDIR)/man1/crystal.1.gz" $(INSTALL) -d -m 0755 "$(DESTDIR)$(DATADIR)/licenses/crystal/" $(INSTALL) -m 644 LICENSE "$(DESTDIR)$(DATADIR)/licenses/crystal/LICENSE" $(INSTALL) -d -m 0755 "$(DESTDIR)$(DATADIR)/bash-completion/completions/" $(INSTALL) -m 644 etc/completion.bash "$(DESTDIR)$(DATADIR)/bash-completion/completions/crystal" $(INSTALL) -d -m 0755 "$(DESTDIR)$(DATADIR)/zsh/site-functions/" $(INSTALL) -m 644 etc/completion.zsh "$(DESTDIR)$(DATADIR)/zsh/site-functions/_crystal" $(INSTALL) -d -m 0755 "$(DESTDIR)$(DATADIR)/fish/vendor_completions.d/" $(INSTALL) -m 644 etc/completion.fish "$(DESTDIR)$(DATADIR)/fish/vendor_completions.d/crystal.fish" ifeq ($(WINDOWS),1) .PHONY: install_dlls install_dlls: $(O)/$(CRYSTAL_BIN) ## Install the compiler's dependent DLLs at DESTDIR (Windows only) $(INSTALL) -d -m 0755 "$(DESTDIR)$(BINDIR)/" @ldd $(O)/$(CRYSTAL_BIN) | grep -iv ' => /c/windows/system32' | sed 's/.* => //; s/ (.*//' | xargs -t -i $(INSTALL) -m 0755 '{}' "$(DESTDIR)$(BINDIR)/" endif .PHONY: uninstall uninstall: ## Uninstall the compiler from DESTDIR rm -f "$(DESTDIR)$(BINDIR)/$(CRYSTAL_BIN)" rm -rf "$(DESTDIR)$(DATADIR)/crystal/src" rm -f "$(DESTDIR)$(MANDIR)/man1/crystal.1.gz" rm -f "$(DESTDIR)$(DATADIR)/licenses/crystal/LICENSE" rm -f "$(DESTDIR)$(DATADIR)/bash-completion/completions/crystal" rm -f "$(DESTDIR)$(DATADIR)/zsh/site-functions/_crystal" rm -f "$(DESTDIR)$(DATADIR)/fish/vendor_completions.d/crystal.fish" .PHONY: install_docs install_docs: docs ## Install docs at DESTDIR $(INSTALL) -d -m 0755 $(DESTDIR)$(DOCDIR) cp -R -P -p docs "$(DESTDIR)$(DOCDIR)/docs" cp -R -P -p samples "$(DESTDIR)$(DOCDIR)/examples" .PHONY: uninstall_docs uninstall_docs: ## Uninstall docs from DESTDIR rm -rf "$(DESTDIR)$(DOCDIR)/docs" rm -rf "$(DESTDIR)$(DOCDIR)/examples" $(O)/all_spec$(EXE): $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @mkdir -p $(O) $(EXPORT_CC) $(EXPORTS) ./bin/crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec/all_spec.cr $(O)/std_spec$(EXE): $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @mkdir -p $(O) $(EXPORT_CC) ./bin/crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec/std_spec.cr $(O)/compiler_spec$(EXE): $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @mkdir -p $(O) $(EXPORT_CC) $(EXPORTS) ./bin/crystal build $(FLAGS) $(COMPILER_FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec/compiler_spec.cr --release $(O)/primitives_spec$(EXE): $(O)/$(CRYSTAL_BIN) $(DEPS) $(SOURCES) $(SPEC_SOURCES) @mkdir -p $(O) $(EXPORT_CC) ./bin/crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec/primitives_spec.cr $(O)/interpreter_spec$(EXE): $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(eval interpreter=1) @mkdir -p $(O) $(EXPORT_CC) ./bin/crystal build $(FLAGS) $(COMPILER_FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec/compiler/interpreter_spec.cr $(O)/$(CRYSTAL_BIN): $(DEPS) $(SOURCES) $(call check_llvm_config) @mkdir -p $(O) $(EXPORTS) $(EXPORTS_BUILD) ./bin/crystal build $(FLAGS) $(COMPILER_FLAGS) -o $(if $(WINDOWS),$(O)/crystal-next.exe,$@) src/compiler/crystal.cr @# NOTE: on MSYS2 it is not possible to overwrite a running program, so the compiler must be first built with @# a different filename and then moved to the final destination. $(if $(WINDOWS),mv $(O)/crystal-next.exe $@) $(LLVM_EXT_OBJ): $(LLVM_EXT_DIR)/llvm_ext.cc $(call check_llvm_config) $(CXX) -c $(CXXFLAGS) -o $@ $< $(if $(LLVM_CONFIG),$(shell $(LLVM_CONFIG) --cxxflags)) man/: $(MAN1PAGES) man/%.gz: man/% gzip -c -9 $< > $@ man/%.1: doc/man/%.adoc SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) asciidoctor -a crystal_version=$(CRYSTAL_VERSION) $< -b manpage -o $@ .PHONY: clean clean: clean_crystal ## Clean up built directories and files rm -rf $(LLVM_EXT_OBJ) rm -rf man/*.gz .PHONY: clean_crystal clean_crystal: ## Clean up crystal built files rm -rf $(O) rm -rf ./docs .PHONY: clean_cache clean_cache: ## Clean up CRYSTAL_CACHE_DIR files rm -rf $(shell ./bin/crystal env CRYSTAL_CACHE_DIR) .PHONY: help help: ## Show this help @echo @printf '\033[34mtargets:\033[0m\n' @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34moptional variables:\033[0m\n' @grep -hE '^[a-zA-Z_-]+ \?=.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = " \\?=.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34mrecipes:\033[0m\n' @grep -hE '^##.*$$' $(MAKEFILE_LIST) |\ awk 'BEGIN {FS = "## "}; /^## [a-zA-Z_-]/ {printf " \033[36m%s\033[0m\n", $$2}; /^## / {printf " %s\n", $$2}' ================================================ FILE: Makefile.win ================================================ all: -include Makefile.win.local # for optional local options e.g. threads # Recipes for this Makefile ## Build the compiler ## $ make -f Makefile.win ## Build the compiler with progress output ## $ make -f Makefile.win progress=1 ## Clean up built files then build the compiler ## $ make -f Makefile.win clean crystal ## Build the compiler in release mode ## $ make -f Makefile.win crystal release=1 interpreter=1 ## Run tests ## $ make -f Makefile.win test ## Run stdlib tests ## $ make -f Makefile.win std_spec ## Run compiler tests ## $ make -f Makefile.win compiler_spec ## Run generators (Unicode, SSL config, ...) ## $ make -B generate_data CRYSTAL ?= crystal ## which previous crystal compiler use release ?= ## Compile in release mode stats ?= ## Enable statistics output progress ?= ## Enable progress output threads ?= ## Maximum number of threads to use debug ?= ## Add symbolic debug info verbose ?= ## Run specs in verbose mode junit_output ?= ## Path to output junit results static ?= ## Enable static linking target ?= ## Cross-compilation target interpreter ?= ## Enable interpreter feature check ?= ## Enable only check when running format order ?=random ## Enable order for spec execution (values: "default" | "random" | seed number) docs_sanitizer ?= ## Enable sanitization for documentation generation sequential_codegen ?= ## Enforce sequential codegen in compiler builds. Base compiler before Crystal 1.8 cannot build with `-Dpreview_mt` MAKEFLAGS += --no-builtin-rules .SUFFIXES: SHELL := cmd.exe CXX := cl.exe RC := rc.exe GLOB = $(shell dir $1 /B /S) MKDIR = if not exist $1 mkdir $1 CP = copy /B /Y $1 $2 CPDIR = robocopy /E /NJH /NJS /NS /NC /NP $1 $2 & if %%ERRORLEVEL%% GEQ 8 exit /B 1 INSTALL = copy /B /Y $1 $2 INSTALLDIR = robocopy /E /NJH /NJS /NS /NC /NP $1 $2 & if %%ERRORLEVEL%% GEQ 8 exit /B 1 MV = move /Y $1 $2 RM = if exist $1 del /F /Q $1 RMDIR = if exist $1 rd /S /Q $1 O := .build SOURCES := $(call GLOB,src\\*.cr) SPEC_SOURCES := $(call GLOB,spec\\*.cr) override FLAGS += -D strict_multi_assign -D preview_overload_order $(if $(release),--release )$(if $(stats),--stats )$(if $(progress),--progress )$(if $(threads),--threads $(threads) )$(if $(debug),-d )$(if $(static),--static )$(if $(LDFLAGS),--link-flags="$(LDFLAGS)" )$(if $(target),--cross-compile --target $(target) ) # NOTE: USE_PCRE1 is only used for testing compatibility with legacy environments that don't provide libpcre2. # Newly built compilers should never be distributed with libpcre to ensure syntax consistency. override COMPILER_FLAGS += $(if $(interpreter),,-Dwithout_interpreter )$(if $(docs_sanitizer),,-Dwithout_libxml2 ) -Dwithout_openssl -Dwithout_zlib$(if $(sequential_codegen),, -Dpreview_mt -Dexecution_context) $(if $(USE_PCRE1),-Duse_pcre,-Duse_pcre2) SPEC_WARNINGS_OFF := --exclude-warnings spec\std --exclude-warnings spec\compiler --exclude-warnings spec\primitives --exclude-warnings src\float\printer SPEC_FLAGS := $(if $(verbose),-v )$(if $(junit_output),--junit_output $(junit_output) )$(if $(order),--order=$(order) ) CRYSTAL_CONFIG_LIBRARY_PATH := $$ORIGIN\lib CRYSTAL_CONFIG_BUILD_COMMIT := $(shell git rev-parse --short HEAD) CRYSTAL_CONFIG_PATH := $$ORIGIN\src ifndef CRYSTAL_VERSION CRYSTAL_VERSION := $(shell type src\VERSION) endif ifndef SOURCE_DATE_EPOCH SOURCE_DATE_EPOCH := $(or $(shell type src\SOURCE_DATE_EPOCH 2>NUL),$(shell git show -s --format=%ct HEAD)) endif export_vars = $(eval export CRYSTAL_CONFIG_BUILD_COMMIT CRYSTAL_CONFIG_PATH SOURCE_DATE_EPOCH) export_build_vars = $(eval export CRYSTAL_CONFIG_LIBRARY_PATH) ifeq ($(LLVM_VERSION),) LLVM_CONFIG ?= LLVM_VERSION := $(if $(LLVM_CONFIG),$(shell "$(LLVM_CONFIG)" --version)) endif LLVM_EXT_DIR = src\llvm\ext LLVM_EXT_OBJ = $(LLVM_EXT_DIR)\llvm_ext.obj CXXFLAGS += $(if $(static),$(if $(debug),/MTd /Od ,/MT ),$(if $(debug),/MDd /Od ,/MD )) prefix ?= $(or $(ProgramW6432),$(ProgramFiles))\crystal BINDIR ?= $(prefix) LIBDIR ?= $(prefix)\lib SRCDIR ?= $(prefix)\src DATADIR ?= $(prefix) colorize = $(info $1) DEPS = $(LLVM_EXT_OBJ) ifneq ($(LLVM_VERSION),) ifeq ($(shell if $(firstword $(subst ., ,$(LLVM_VERSION))) GEQ 18 echo 0),0) DEPS = endif endif check_llvm_config = $(eval \ check_llvm_config := $(if $(LLVM_VERSION),\ $(call colorize,Using $(or $(LLVM_CONFIG),externally configured LLVM) [version=$(LLVM_VERSION)]),\ $(error "Could not locate compatible llvm-config, make sure it is installed and in your PATH, or set LLVM_VERSION / LLVM_CONFIG. Compatible versions: $(shell type src\llvm\ext\llvm-versions.txt)))\ ) .PHONY: all all: crystal ## Build all files (currently crystal only) [default] .PHONY: test test: spec ## Run tests .PHONY: spec spec: std_spec primitives_spec compiler_spec .PHONY: std_spec std_spec: $(O)\std_spec.exe ## Run standard library specs $(O)\std_spec $(SPEC_FLAGS) .PHONY: compiler_spec compiler_spec: $(O)\compiler_spec.exe ## Run compiler specs $(O)\compiler_spec $(SPEC_FLAGS) .PHONY: primitives_spec primitives_spec: $(O)\primitives_spec.exe ## Run primitives specs $(O)\primitives_spec $(SPEC_FLAGS) .PHONY: interpreter_spec interpreter_spec: $(O)\interpreter_spec ## Run interpreter specs $(O)\interpreter_spec $(SPEC_FLAGS) .PHONY: smoke_test smoke_test: ## Build specs as a smoke test smoke_test: $(O)\std_spec.exe $(O)\compiler_spec.exe $(O)\crystal.exe .PHONY: all_spec all_spec: $(O)\all_spec.exe ## Run all specs (note: this builds a huge program; `test` recipe builds individual binaries and is recommended for reduced resource usage) $(O)\all_spec $(SPEC_FLAGS) .PHONY: samples samples: ## Build example programs $(MAKE) -C samples -f $(MAKEFILE_LIST) .PHONY: docs docs: ## Generate standard library documentation $(call check_llvm_config) .\bin\crystal docs src\docs_main.cr $(DOCS_OPTIONS) --project-name=Crystal --project-version=$(CRYSTAL_VERSION) --source-refname=$(CRYSTAL_CONFIG_BUILD_COMMIT) .PHONY: crystal crystal: $(O)\crystal.exe ## Build the compiler .PHONY: deps llvm_ext deps: $(DEPS) ## Build dependencies llvm_ext: $(LLVM_EXT_OBJ) .PHONY: format format: ## Format sources .\bin\crystal tool format$(if $(check), --check) src spec samples scripts .PHONY: generate_data generate_data: ## Run generator scripts for Unicode, SSL config, ... $(MAKE) -B -f scripts/generate_data.mk .PHONY: install install: $(O)\crystal.exe ## Install the compiler at prefix $(call MKDIR,"$(BINDIR)") $(call INSTALL,"$(O)\crystal.exe","$(BINDIR)\crystal.exe") $(call INSTALL,"$(O)\crystal.pdb","$(BINDIR)\crystal.pdb") $(call MKDIR,"$(DATADIR)") $(call INSTALLDIR,src,"$(DATADIR)\src") $(call RM,"$(DATADIR)\$(LLVM_EXT_OBJ)") $(call INSTALL,LICENSE,"$(DATADIR)\LICENSE.txt") .PHONY: uninstall uninstall: ## Uninstall the compiler from prefix $(call RM,"$(DATADIR)\LICENSE.txt") $(call RMDIR,"$(DATADIR)\src") $(call RM,"$(BINDIR)\crystal.exe") $(call RM,"$(BINDIR)\crystal.pdb") .PHONY: install_docs install_docs: docs ## Install docs at prefix $(call MKDIR,"$(DATADIR)") $(call INSTALLDIR,docs,"$(DATADIR)\docs") $(call INSTALLDIR,samples,"$(DATADIR)\examples") .PHONY: uninstall_docs uninstall_docs: ## Uninstall docs from prefix $(call RMDIR,"$(DATADIR)\docs") $(call RMDIR,"$(DATADIR)\examples") $(O)\all_spec.exe: $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @$(call MKDIR,"$(O)") $(call export_vars) .\bin\crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o "$@" spec\all_spec.cr $(O)\std_spec.exe: $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @$(call MKDIR,"$(O)") .\bin\crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o "$@" spec\std_spec.cr $(O)\compiler_spec.exe: $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(call check_llvm_config) @$(call MKDIR,"$(O)") $(call export_vars) .\bin\crystal build $(FLAGS) $(COMPILER_FLAGS) $(SPEC_WARNINGS_OFF) -o "$@" spec\compiler_spec.cr --release $(O)\primitives_spec.exe: $(O)\crystal.exe $(DEPS) $(SOURCES) $(SPEC_SOURCES) @$(call MKDIR,"$(O)") .\bin\crystal build $(FLAGS) $(SPEC_WARNINGS_OFF) -o "$@" spec\primitives_spec.cr $(O)\interpreter_spec: $(DEPS) $(SOURCES) $(SPEC_SOURCES) $(eval interpreter=1) @$(call MKDIR, "$(O)") .\bin\crystal build $(FLAGS) $(COMPILER_FLAGS) $(SPEC_WARNINGS_OFF) -o $@ spec\compiler\interpreter_spec.cr $(O)\crystal.exe: $(DEPS) $(SOURCES) $(O)\crystal.res $(call check_llvm_config) @$(call MKDIR,"$(O)") $(call export_vars) $(call export_build_vars) .\bin\crystal build $(FLAGS) $(COMPILER_FLAGS) -o "$(O)\crystal-next.exe" src\compiler\crystal.cr --link-flags=/PDBALTPATH:crystal.pdb "--link-flags=$(realpath $(O)\crystal.res)" $(call MV,"$(O)\crystal-next.exe","$@") $(call MV,"$(O)\crystal-next.pdb","$(O)\crystal.pdb") $(O)\crystal.res: $(O)\crystal.rc @$(call MKDIR,"$(O)") $(RC) /nologo /Fo "$@" "$<" $(O)\crystal.rc: $(MAKEFILE_LIST) @$(call MKDIR,"$(O)") $(MAKE) -s -f $(MAKEFILE_LIST) rc > "$@" $(LLVM_EXT_OBJ): $(LLVM_EXT_DIR)\llvm_ext.cc $(call check_llvm_config) @rem Disable some harmless warnings: @rem - warning C4244: 'initializing': conversion from '_Ty' to '_Ty2', possible loss of data @rem - warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc @rem - warning C4624: '...': destructor was implicitly defined as deleted $(CXX) /nologo /c $(CXXFLAGS) /WX /wd4244 /wd4624 /wd4530 "/Fo$@" "$<" $(if $(LLVM_CONFIG),$(shell $(LLVM_CONFIG) --cxxflags)) .PHONY: clean clean: clean_crystal ## Clean up built directories and files $(call RM,"$(LLVM_EXT_OBJ)") .PHONY: clean_crystal clean_crystal: ## Clean up crystal built files $(call RMDIR,"$(O)") $(call RMDIR,docs) .PHONY: clean_cache clean_cache: ## Clean up CRYSTAL_CACHE_DIR files $(call RMDIR,"$(shell .\bin\crystal env CRYSTAL_CACHE_DIR)") .PHONY: rc rc: ## Write compiler resource script to standard output $(eval comma := ,) $(eval ver_comma := $(subst .,$(comma),$(subst -dev,,$(CRYSTAL_VERSION)))) $(eval source_date := $(shell git show -s --format=%cs HEAD)) $(eval source_year := $(firstword $(subst -, ,$(source_date)))) $(eval ver_full := $(CRYSTAL_VERSION)$(if $(CRYSTAL_CONFIG_BUILD_COMMIT), [$(CRYSTAL_CONFIG_BUILD_COMMIT)])$(if $(source_date), ($(source_date)))) @setlocal EnableDelayedExpansion &\ echo #include ^&\ echo.&\ set "_dir=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))" &\ echo 1 ICON ^"!_dir:/=\\!src\\compiler\\crystal\\tools\\playground\\public\\favicon.ico^"&\ echo.&\ echo VS_VERSION_INFO VERSIONINFO&\ echo PRODUCTVERSION $(ver_comma),0&\ echo FILEVERSION $(ver_comma),1&\ echo FILEFLAGSMASK VS_FFI_FILEFLAGSMASK&\ echo FILEFLAGS $(if $(findstring -dev,$(CRYSTAL_VERSION)),VS_FF_PRERELEASE,0)&\ echo FILEOS VOS_NT_WINDOWS32&\ echo FILETYPE VFT_APP&\ echo FILESUBTYPE VFT2_UNKNOWN&\ echo BEGIN&\ echo BLOCK "StringFileInfo"&\ echo BEGIN&\ echo BLOCK "040904B0"&\ echo BEGIN&\ echo VALUE "ProductName", "Crystal"&\ echo VALUE "ProductVersion", "$(ver_full)"&\ echo VALUE "FileVersion", "$(ver_full)"&\ echo VALUE "FileDescription", "Crystal$(if $(LLVM_CONFIG), $(shell $(LLVM_CONFIG) --host-target))"&\ echo VALUE "Comments", "$(if $(LLVM_VERSION),LLVM $(LLVM_VERSION))"&\ echo VALUE "InternalName", "crystal.exe"&\ echo VALUE "OriginalFilename", "crystal.exe"&\ echo VALUE "CompanyName", "Manas Technology Solutions"&\ echo VALUE "LegalCopyright", "Copyright 2012-$(source_year) Manas Technology Solutions"&\ echo END&\ echo END&\ echo BLOCK "VarFileInfo"&\ echo BEGIN&\ echo VALUE "Translation", 0x0409, 0x04B0&\ echo END&\ echo END .PHONY: help help: ## Show this help @setlocal EnableDelayedExpansion &\ echo. &\ echo targets: &\ (for /F "usebackq tokens=1* delims=:" %%g in ($(MAKEFILE_LIST)) do (\ if not "%%h" == "" (\ set "_line=%%g " &\ set "_rest=%%h" &\ set "_comment=!_rest:* ## =!" &\ if not "!_comment!" == "!_rest!"\ if "!_line:_rest=!" == "!_line!"\ echo !_line:~0,16!!_comment!\ )\ )) &\ echo. &\ echo optional variables: &\ (for /F "usebackq tokens=1,3 delims=?#" %%g in ($(MAKEFILE_LIST)) do (\ if not "%%h" == "" (\ set "_var=%%g " &\ echo !_var:~0,14! %%h\ )\ )) &\ echo. &\ echo recipes: &\ (for /F "usebackq tokens=* delims=" %%g in ($(MAKEFILE_LIST)) do (\ set "_line=%%g" &\ if "!_line:~0,7!" == "## $$ " (\ echo !_name! &\ echo !_line:~2!\ ) else if "!_line:~0,3!" == "## "\ set "_name= !_line:~3!"\ )) ================================================ FILE: NOTICE.md ================================================ # Crystal Programming Language Copyright 2012-2026 Manas Technology Solutions. This product includes software developed at Manas Technology Solutions (). Apache License v2.0 with Swift exception applies to all works unless specified otherwise: Please see [REUSE.toml](REUSE.toml) and [LICENSE](LICENSE) for additional copyright and licensing information. - This repository includes vendored libraries (shards) in `/lib/` which have their own licenses. See [REUSE.toml](REUSE.toml) for details. - Crystal playground includes vendored libraries with their own licenses. See [src/compiler/crystal/tools/playground/public/vendor/REUSE.toml](src/compiler/crystal/tools/playground/public/vendor/REUSE.toml) for details. ## External libraries information Crystal compiler links the following libraries, which have their own license: - [LLVM][] - [Apache-2.0 with LLVM exceptions][] - [PCRE or PCRE2][] - [BSD-3][] - [libevent2][] - [BSD-3][] - [libiconv][] - [LGPLv3][] - [bdwgc][] - [MIT][] Crystal compiler calls the following tools as external process on compiling, which have their own license: - [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) - [GPLv3] Crystal standard library uses the following libraries, which have their own licenses: - [LLVM][] - [Apache-2.0 with LLVM exceptions][] - [PCRE or PCRE2][] - [BSD-3][] - [libevent2][] - [BSD-3][] - [libiconv][] - [LGPLv3][] - [bdwgc][] - [MIT][] - [Zlib][] - [Zlib][Zlib-license] - [OpenSSL][] - [Apache-2.0][] - [Libxml2][] - [MIT][] - [LibYAML][] - [MIT][] - [readline][] - [GPLv3][] - [GMP][] - [LGPLv3][] [Apache-2.0]: https://www.openssl.org/source/apache-license-2.0.txt [Apache-2.0 with LLVM exceptions]: https://raw.githubusercontent.com/llvm/llvm-project/main/llvm/LICENSE.TXT [BSD-3]: https://opensource.org/licenses/BSD-3-Clause [GPLv3]: https://www.gnu.org/licenses/gpl-3.0.en.html [LGPLv3]: https://www.gnu.org/licenses/lgpl-3.0.en.html [MIT]: https://opensource.org/licenses/MIT [Zlib-license]: https://opensource.org/licenses/Zlib [bdwgc]: http://www.hboehm.info/gc/ [GMP]: https://gmplib.org/ [libevent2]: http://libevent.org/ [libiconv]: https://www.gnu.org/software/libiconv/ [Libxml2]: http://xmlsoft.org/ [LibYAML]: http://pyyaml.org/wiki/LibYAML [LLVM]: http://llvm.org/ [OpenSSL]: https://www.openssl.org/ [PCRE or PCRE2]: http://pcre.org/ [readline]: https://tiswww.case.edu/php/chet/readline/rltop.html [Zlib]: http://www.zlib.net/ ================================================ FILE: README.md ================================================ # Crystal [![Linux CI Build Status](https://github.com/crystal-lang/crystal/workflows/Linux%20CI/badge.svg)](https://github.com/crystal-lang/crystal/actions?query=workflow%3A%22Linux+CI%22+event%3Apush+branch%3Amaster) [![macOS CI Build Status](https://github.com/crystal-lang/crystal/workflows/macOS%20CI/badge.svg)](https://github.com/crystal-lang/crystal/actions?query=workflow%3A%22macOS+CI%22+event%3Apush+branch%3Amaster) [![AArch64 CI Build Status](https://github.com/crystal-lang/crystal/workflows/AArch64%20CI/badge.svg)](https://github.com/crystal-lang/crystal/actions?query=workflow%3A%22AArch64+CI%22+event%3Apush+branch%3Amaster) [![Windows CI Build Status](https://github.com/crystal-lang/crystal/workflows/Windows%20CI/badge.svg)](https://github.com/crystal-lang/crystal/actions?query=workflow%3A%22Windows+CI%22+event%3Apush+branch%3Amaster) [![CircleCI Build Status](https://circleci.com/gh/crystal-lang/crystal/tree/master.svg?style=shield)](https://circleci.com/gh/crystal-lang/crystal) [![Join the chat at https://gitter.im/crystal-lang/crystal](https://badges.gitter.im/crystal-lang/crystal.svg)](https://gitter.im/crystal-lang/crystal) [![Code Triagers Badge](https://www.codetriage.com/crystal-lang/crystal/badges/users.svg)](https://www.codetriage.com/crystal-lang/crystal) --- [![Crystal - Born and raised at Manas](doc/assets/crystal-born-and-raised.svg)](https://manas.tech/) Crystal is a programming language with the following goals: - Have a syntax similar to Ruby (but compatibility with it is not a goal) - Statically type-checked but without having to specify the type of variables or method arguments. - Be able to call C code by writing bindings to it in Crystal. - Have compile-time evaluation and generation of code, to avoid boilerplate code. - Compile to efficient native code. ## Why? We love Ruby's efficiency for writing code. We love C's efficiency for running code. We want the best of both worlds. We want the compiler to understand what we mean without having to specify types everywhere. We want full OOP. Oh, and we don't want to write C code to make the code run faster. ## Project Status Within a major version, language features won't be removed or changed in any way that could prevent a Crystal program written with that version from compiling and working. The built-in standard library might be enriched, but it will always be done with backwards compatibility in mind. Development of the Crystal language is possible thanks to the community's effort and the continued support of [84codes](https://www.84codes.com/) and every other [sponsor](https://crystal-lang.org/sponsors). ## Installing [Follow these installation instructions](https://crystal-lang.org/install) ## Try it online [play.crystal-lang.org](https://play.crystal-lang.org/) ## Documentation - [Language Reference](http://crystal-lang.org/reference) - [Standard library API](https://crystal-lang.org/api) - [Roadmap](https://github.com/crystal-lang/crystal/wiki/Roadmap) ## Community Have any questions or suggestions? Ask on the [Crystal Forum](https://forum.crystal-lang.org), on our [Gitter channel](https://gitter.im/crystal-lang/crystal) or IRC channel [#crystal-lang](https://web.libera.chat/#crystal-lang) at irc.libera.chat, or on Stack Overflow under the [crystal-lang](http://stackoverflow.com/questions/tagged/crystal-lang) tag. There is also an archived [Google Group](https://groups.google.com/forum/?fromgroups#!forum/crystal-lang). ## Contributing The Crystal repository is hosted at [crystal-lang/crystal](https://github.com/crystal-lang/crystal) on GitHub. Read the general [Contributing guide](https://github.com/crystal-lang/crystal/blob/master/CONTRIBUTING.md), and then: 1. Fork it () 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request ================================================ FILE: REUSE.toml ================================================ version = 1 # All original code in this repository is licensed under Apache 2.0 with Swift # exception. [[annotations]] path = ["**"] SPDX-FileCopyrightText = "Copyright 2012-2026 Manas Technology Solutions." SPDX-License-Identifier = "Apache-2.0 WITH Swift-exception" # Unset license information for vendored libraries ("shards"). They either # provide their own information or there's a specific section in this file. [[annotations]] path = ["lib/*/**"] [[annotations]] path = "lib/markd/**" SPDX-FileCopyrightText = "Copyright (c) 2017-present icyleaf" SPDX-License-Identifier = "MIT" [[annotations]] path = "lib/reply/**" SPDX-FileCopyrightText = "Copyright (c) 2022 I3oris " SPDX-License-Identifier = "MIT" [[annotations]] path = "lib/sanitize/**" SPDX-FileCopyrightText = "Copyright (c) 2020 Johannes Müller " SPDX-License-Identifier = "Apache-2.0" ================================================ FILE: SECURITY.md ================================================ # Reporting a Vulnerability Should you find any security-related issue, please _do not share them openly_ in the issue tracker. We have a dedicated mailbox where we keep track of them: You can encrypt your message via [Keybase](https://keybase.io/encrypt) (set recipient `crystal`) or with our [PGP key](https://crystal-lang.org/community/crystal-pgp-key.txt) (fingerprint `5995 C83C D754 BE44 8164 1929 0961 7FD3 7CC0 6B54`) also available on [Keybase server](https://keybase.io/crystal/pgp_keys.asc). ================================================ FILE: UPGRADING.md ================================================ # Upgrading This guide provides instructions for upgrading Crystal from one release to the next. Upgrades must be run sequentially, meaning you should not skip minor/major releases while upgrading. Crystal commits to a backwards-compatibility guarantee that code should continue to work with all future minor releases of the same major release series. Still, even bug fixes introduce changes that may break existing code in some edge cases. We're only listing the most relevant changes here that could have a relevant impact. The [changelogs](./doc/changelogs/README.md) contain more information about all changes in a specific release. ## Crystal 1.13 - `CRYSTAL_LIBRARY_RPATH` and the `preview_win32_delay_load` feature flag have been removed. Individual DLLs can be explicitly delay-loaded with the MSVC toolchain by using `/DELAYLOAD` as a linker flag. Similarly RPATH can be added with GCC or Clang toolchains by adding `-Wl,-rpath`. ## Crystal 1.9 - The implementation of the comparison operator `#<=>` between `Big*` (`BigDecimal`, `BigFloat`, `BigInt`, `BigRational`) and `Float` (`Float32`, `Float64`) number types is now nilable. When invoking these comparisons, `Nil` values must be handled. ================================================ FILE: _typos.toml ================================================ [default.extend-words] flate = "flate" [default.extend-identifiers] ACCES = "ACCES" ba = "ba" ba2 = "ba2" bui = "bui" category_Nd = "category_Nd" DW_AT_endianity = "DW_AT_endianity" EXTA = "EXTA" GC_get_thr_restart_signal = "GC_get_thr_restart_signal" get_thr_restart_signal = "get_thr_restart_signal" IPPROTO_ND = "IPPROTO_ND" IST = "IST" iTolen = "iTolen" iy = "iy" larg = "larg" Nd = "Nd" numer = "numer" OLT = "OLT" pendings = "pendings" RELA = "RELA" RPC_S_CALL_FAILED_DNE = "RPC_S_CALL_FAILED_DNE" SEH = "SEH" setup_seh_handler = "setup_seh_handler" usri4_parms = "usri4_parms" msg_controllen = "msg_controllen" __crystal_sigfault_handler = "__crystal_sigfault_handler" TunkShif = "TunkShif" [default] extend-ignore-re = [ # numeric literals '0x[0-9a-fA-F_\.\+]+([fiu](8|16|32|64|128))?', '\\u\{[0-9a-fA-F]+\}', # proper names 'FLE Standard Time', 'Universally Unique IDentifier', # constants 'ERROR_\w+', 'EVP_CIPH.*', # fixed test values 'FOO|/Fo', 'rCVZVOThsIa97pEDOxvGu', '\w*AAAAAAAA\w*', # several string specs '"(Fo-ur|thi|abd|alo|tro|tring|ue)"', '"(aGFo|hel|Hel|thr|noe|Noe|BaR|fo|FO)', '(hel|Hel|worl|Worl|fo)"', '/fo|/FO', "'fo", "/\\(fo", 'tr‸ue|fo‸o', "\"[^\"]+\"\\.to_slice\\s*=> [\"']\\\\u", # src/html/entities.cr " ([a-zA-Z.]{8} ){4}->", # src/bit_array.cr "[A-z]+[0-9]+", # words including a number are likely some kind of identifier "sha256[:-][0-9A-z=]+", # shell.nix ] [files] extend-exclude = [ ".git/**", "lib/**", "man/**", "spec/compiler/semantic/did_you_mean_spec.cr", "spec/std/string_scanner_spec.cr", "spec/std/data/**", "spec/std/string/grapheme_break_spec.cr", "src/compiler/crystal/tools/playground/public/vendor/", ] ================================================ FILE: bin/check-compiler-flag ================================================ #!/bin/sh # Use `./bin/check-compiler-flag FLAG` to check the behaviour of the given compiler flag. # This is useful if `crystal build` is affected when using `-DFLAG` option. # # This script will # * run the compiler_spec using the flag # * build the compiler to have the flag available (in case the flag is introduced in this version) # * run the std_spec and primitives_spec with and without the flag # * check the compiler_spec built with and without the flag (eg: the specs build with the flag can generate a compiler without the flag) # * build a 2nd generation of the compiler using the flag # * repeat the checks for the spec suites with and without the flag set -eux COMPILER_FLAG=$1 # test compiler_specs make clean_cache clean_crystal CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) CRYSTAL_SPEC_COMPILER_FLAGS="$COMPILER_FLAG" make compiler_spec # first gen compiler make clean_cache clean_crystal crystal ./bin/crystal --version md5 .build/crystal # run specs make clean_cache std_spec make clean_cache std_spec FLAGS="-D$COMPILER_FLAG" make clean_cache primitives_spec make clean_cache primitives_spec FLAGS="-D$COMPILER_FLAG" # test compiler_specs make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) CRYSTAL_SPEC_COMPILER_FLAGS="$COMPILER_FLAG" make compiler_spec FLAGS="-D$COMPILER_FLAG" make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) make compiler_spec FLAGS="-D$COMPILER_FLAG" make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) make compiler_spec # building 2nd gen compiler make clean_crystal clean_cache crystal # first md5 .build/crystal touch src/compiler/crystal.cr sleep 2 make clean_cache crystal FLAGS="-D$COMPILER_FLAG" # second md5 .build/crystal # run specs make clean_cache std_spec make clean_cache std_spec FLAGS="-D$COMPILER_FLAG" make clean_cache primitives_spec make clean_cache primitives_spec FLAGS="-D$COMPILER_FLAG" # run compiler specs make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) CRYSTAL_SPEC_COMPILER_FLAGS="$COMPILER_FLAG" make compiler_spec FLAGS="-D$COMPILER_FLAG" make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) make compiler_spec FLAGS="-D$COMPILER_FLAG" make clean_cache CRYSTAL_LIBRARY_PATH=$(./bin/crystal env CRYSTAL_LIBRARY_PATH) make compiler_spec ================================================ FILE: bin/ci ================================================ #!/bin/sh fail() { echo "${*}" >&2 exit 1 } on_tag() { if [ -n "$CURRENT_TAG" ]; then echo "${*}" eval "${*}" return $? else return 0 fi } fail_on_error() { "${@}" exit=$? if [ "$exit" -ne "0" ]; then fail "${*} exited with $exit" fi return 0 } verify_environment() { if [ -z "$TRAVIS_OS_NAME" ]; then fail "\$TRAVIS_OS_NAME is not set or empty." fi } verify_linux_environment() { if [ -z "$ARCH" ]; then fail "\$ARCH is not set or empty." fi if [ -z "$ARCH_CMD" ]; then fail "\$ARCH_CMD is not set or empty." fi } on_os() { os="$1" shift if [ -z "$CI_NIX_SHELL" ]; then verify_environment if [ "$TRAVIS_OS_NAME" = "$os" ]; then echo "${*}" eval "${*}" return $? else return 0 fi else return 0 fi } on_linux() { fail_on_error on_os "linux" "${*}" } on_osx() { fail_on_error on_os "osx" "${*}" } on_nix_shell_eval() { if [ -n "$CI_NIX_SHELL" ]; then echo "${*}" eval "${*}" return $? else return 0 fi } on_nix_shell() { fail_on_error on_nix_shell_eval "${*}" } on_github() { if [ "$GITHUB_ACTIONS" = "true" ]; then eval "${*}" return $? else return 0 fi } prepare_system() { on_linux 'echo '"'"'{"ipv6":true, "fixed-cidr-v6":"2001:db8:1::/64"}'"'"' | sudo tee /etc/docker/daemon.json' on_linux sudo service docker restart } build() { with_build_env 'bin/crystal scripts/print_regex_config.cr' with_build_env 'make std_spec clean threads=1 junit_output=.junit/std_spec.xml' case $ARCH in i386) with_build_env 'make crystal threads=1' with_build_env 'SPEC_SPLIT="0%4" make std_spec threads=1 junit_output=.junit/std_spec.0.xml' with_build_env 'SPEC_SPLIT="1%4" make std_spec threads=1 junit_output=.junit/std_spec.1.xml' with_build_env 'SPEC_SPLIT="2%4" make std_spec threads=1 junit_output=.junit/std_spec.2.xml' with_build_env 'SPEC_SPLIT="3%4" make std_spec threads=1 junit_output=.junit/std_spec.3.xml' parts=16 i=0 while [ $i -lt $parts ]; do with_build_env "CRYSTAL_SPEC_COMPILER_THREADS=1 SPEC_SPLIT=\"$i%$parts\" make compiler_spec threads=1 junit_output=.junit/compiler_spec.$i.xml" i=$((i + 1)) done with_build_env 'make primitives_spec threads=1 junit_output=.junit/primitives_spec.xml' with_build_env 'make docs threads=1' ;; *) with_build_env 'make crystal primitives_spec std_spec compiler_spec docs threads=1 junit_output=.junit/spec.xml DOCS_OPTIONS="--json-config-url=/api/versions.json --canonical-base-url=https://crystal-lang.org/api/latest/"' ;; esac with_build_env 'make samples' with_build_env 'CRYSTAL_OPTS=--debug make samples' } format() { with_build_env 'make clean crystal format threads=1 check=1' } prepare_build() { on_linux verify_linux_environment on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1-darwin-universal.tar.gz -o ~/crystal.tar.gz on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.19.1-1 crystal;popd' # These commands may take a few minutes to run due to the large size of the repositories. # This restriction has been made on GitHub's request because updating shallow # clones is an extremely expensive operation due to the tree layout and # traffic of Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do # this for you automatically to avoid repeatedly performing an expensive # unshallow operation in CI systems (which should instead be fixed to not use # shallow clones). Sorry for the inconvenience! on_osx git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow on_osx git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow on_osx brew update --preinstall on_osx brew bundle --no-lock # Install a recent bash version for nix-shell. # macos ships with an ancient one. if [ "$(uname)" = "Darwin" ]; then on_nix_shell "brew install bash" fi # initialize nix environment on_nix_shell nix-shell # Note: brew link --force might show: # Warning: Refusing to link macOS-provided software: llvm # # If you need to have llvm first in your PATH run: # echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.bash_profile # # This is added in the .circleci/config.yml on_tag verify_version } verify_version() { # If building a tag, check it matches with file FILE_VERSION=$(cat ./src/VERSION) if [ "$FILE_VERSION" != "$CURRENT_TAG" ] then fail "VERSION ($FILE_VERSION) does not match GIT TAG ($CURRENT_TAG)" fi } with_build_env() { command="$1" on_github "echo '::group::$1'" # Ensure non GMT timezone export TZ="America/New_York" on_linux verify_linux_environment export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:="crystallang/crystal:${CRYSTAL_BOOTSTRAP_VERSION:-1.19.1}"}" case $ARCH in aarch64|x86_64) export DOCKER_TEST_IMAGE="$DOCKER_TEST_PREFIX-build" ;; aarch64-musl|x86_64-musl) export DOCKER_TEST_IMAGE="$DOCKER_TEST_PREFIX-alpine-build" ;; i386) export DOCKER_TEST_IMAGE="$DOCKER_TEST_PREFIX-i386-build" ;; esac on_linux docker run \ --rm -t \ -u "$(id -u)" \ -v "$PWD":/mnt \ -v /etc/passwd:/etc/passwd \ -v /etc/group:/etc/group \ -w /mnt \ -e CRYSTAL_CACHE_DIR="/tmp/crystal" \ -e SPEC_SPLIT_DOTS \ -e USE_PCRE1 \ "$DOCKER_TEST_IMAGE" \ "$ARCH_CMD" /bin/sh -c "'$command'" on_osx sudo systemsetup -settimezone $TZ on_osx PATH="~/crystal/bin:\$PATH" \ CRYSTAL_LIBRARY_PATH="~/crystal/embedded/lib" \ CRYSTAL_CACHE_DIR="/tmp/crystal" \ /bin/sh -c "'$command'" # shellcheck disable=SC2086 on_nix_shell nix-shell --pure $CI_NIX_SHELL_ARGS --run "'TZ=$TZ $command'" on_github echo "::endgroup::" } usage() { cat </dev/null && pwd -P; } } _canonicalize_file_path() ( dir=$(dirname -- "$1") file=$(basename -- "$1") { cd "$dir" 2>/dev/null >/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file"; } ) ############################################################################## # Based on http://stackoverflow.com/q/370047/641451 remove_path_item() ( path="$1" printf "%s" "$path" | awk -v item="$2" -v RS=: -v ORS=: '$0 != item' | sed 's/:$//' ) ############################################################################## __has_colors() ( num_colors=$(tput colors 2>/dev/null) if [ -n "$num_colors" ] && [ "$num_colors" -gt 2 ]; then return 0 else return 1 fi ) __error_msg() { if __has_colors; then # bold red coloring printf '%b\n' "\033[31;1m$*\033[0m" 1>&2 else printf '%b\n' "$@" 1>&2 fi } __warning_msg() { if __has_colors; then # brown coloring printf '%b\n' "\033[33m$*\033[0m" 1>&2 else printf '%b\n' "$@" 1>&2 fi } SCRIPT_PATH="$(realpath "$0")" SCRIPT_ROOT="$(dirname "$SCRIPT_PATH")" CRYSTAL_ROOT="$(dirname "$SCRIPT_ROOT")" CRYSTAL_DIR="$CRYSTAL_ROOT/.build" export CRYSTAL_PATH="${CRYSTAL_PATH:-./lib:$CRYSTAL_ROOT/src}" if [ -n "${CRYSTAL_PATH##*"$CRYSTAL_ROOT"/src*}" ]; then __warning_msg "CRYSTAL_PATH env variable does not contain $CRYSTAL_ROOT/src" fi export CRYSTAL_HAS_WRAPPER=true : "${CRYSTAL=crystal}" PARENT_CRYSTAL="$CRYSTAL" # check if the parent crystal command is a path that refers to this script if [ -z "${PARENT_CRYSTAL##*/*}" ] && [ "$(realpath "$PARENT_CRYSTAL")" = "$SCRIPT_PATH" ]; then # ignore it and use `crystal` as parent compiler command PARENT_CRYSTAL="crystal" fi # check if the parent crystal command refers to this script if [ "$(realpath "$(command -v "$PARENT_CRYSTAL" 2> /dev/null)" 2> /dev/null)" = "$SCRIPT_PATH" ]; then # remove the path to this script from PATH NEW_PATH="$(remove_path_item "$(remove_path_item "$PATH" "$SCRIPT_ROOT")" "bin")" # if the PATH did not change it will lead to an infinite recursion => display error if [ "$NEW_PATH" = "$PATH" ]; then __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable' exit 1 fi PARENT_CRYSTAL=$(PATH=$NEW_PATH command -v "$PARENT_CRYSTAL" 2> /dev/null) if [ "$(realpath "$PARENT_CRYSTAL" 2> /dev/null)" = "$SCRIPT_PATH" ]; then __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable' exit 1 fi fi command -v "$PARENT_CRYSTAL" > /dev/null 2> /dev/null PARENT_CRYSTAL_EXISTS=$(test !$?) if ($PARENT_CRYSTAL_EXISTS); then if [ -z "$CRYSTAL_CONFIG_LIBRARY_PATH" ] || [ -z "$CRYSTAL_LIBRARY_PATH" ]; then CRYSTAL_INSTALLED_LIBRARY_PATH="$($PARENT_CRYSTAL env CRYSTAL_LIBRARY_PATH 2> /dev/null || echo "")" export CRYSTAL_LIBRARY_PATH="${CRYSTAL_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}" export CRYSTAL_CONFIG_LIBRARY_PATH="${CRYSTAL_CONFIG_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}" fi fi # CRYSTAL_PATH has all symlinks resolved. In order to avoid issues with duplicate file # paths when the working directory is a symlink, we cd into the current directory # with symlinks resolved as well (see https://github.com/crystal-lang/crystal/issues/12969). cd "$(realpath "$(pwd)")" || exit case "$(uname -s)" in CYGWIN*|MSYS_NT*|MINGW32_NT*|MINGW64_NT*) CRYSTAL_BIN="crystal.exe" ;; *) CRYSTAL_BIN="crystal" ;; esac # CRYSTAL_EXEC_PATH determines the location of the `crystal` program for external # compiler commands. CRYSTAL_EXEC_PATH="$SCRIPT_ROOT" export CRYSTAL_EXEC_PATH if [ -x "$CRYSTAL_DIR/${CRYSTAL_BIN}" ]; then __warning_msg "Using compiled compiler at ${CRYSTAL_DIR#"$PWD/"}/${CRYSTAL_BIN}" exec "$CRYSTAL_DIR/${CRYSTAL_BIN}" "$@" elif (! $PARENT_CRYSTAL_EXISTS); then __error_msg 'You need to have a crystal executable in your path! or set CRYSTAL env variable' exit 1 else exec "$PARENT_CRYSTAL" "$@" fi ================================================ FILE: bin/crystal.bat ================================================ @echo off powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "%~dp0crystal.ps1" --%% %* ================================================ FILE: bin/crystal.ps1 ================================================ param( [Parameter(Position = 0, ValueFromRemainingArguments)] [string[]] $CrystalArgs ) # https://www.powershellgallery.com/packages/PowerGit/0.6.1/Content/Functions%5CResolve-RealPath.ps1 function Resolve-RealPath { <# .SYNOPSIS Implementation of Unix realpath(). .PARAMETER Path Must exist #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('FullName')] [string] $Path ) if ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) { return [IO.Path]::GetFullPath($Path) } [string[]] $parts = ($Path.TrimStart([IO.Path]::DirectorySeparatorChar).Split([IO.Path]::DirectorySeparatorChar)) [string] $realPath = '' foreach ($part in $parts) { $realPath += [string] ([IO.Path]::DirectorySeparatorChar + $part) $item = Get-Item $realPath if ($item.Target) { $realPath = $item.Target } } $realPath } # adopted from https://stackoverflow.com/a/15669365 function Write-StdErr { <# .SYNOPSIS Writes text to stderr when running in a regular console window, to the host''s error stream otherwise. .DESCRIPTION Writing to true stderr allows you to write a well-behaved CLI as a PS script that can be invoked from a batch file, for instance. Note that PS by default sends ALL its streams to *stdout* when invoked from cmd.exe. #> param( [Parameter(Mandatory)] [string] $Line, $ForegroundColor ) if ($Host.Name -eq 'ConsoleHost') { if ($ForegroundColor) { [Console]::ForegroundColor = $ForegroundColor } [Console]::Error.WriteLine($Line) if ($ForegroundColor) { [Console]::ResetColor() } } else { [void] $host.ui.WriteErrorLine($Line) } } # https://stackoverflow.com/a/43030126 function Invoke-WithEnvironment { <# .SYNOPSIS Invokes commands with a temporarily modified environment. .DESCRIPTION Modifies environment variables temporarily based on a hashtable of values, invokes the specified script block, then restores the previous environment. .PARAMETER Environment A hashtable that defines the temporary environment-variable values. Assign $null to (temporarily) remove an environment variable that is currently set. .PARAMETER ScriptBlock The command(s) to execute with the temporarily modified environment. .EXAMPLE > Invoke-WithEnvironment @{ PORT=8080 } { node index.js } Runs node with environment variable PORT temporarily set to 8080, with its previous value, if any #> param( [Parameter(Mandatory)] [System.Collections.IDictionary] $Environment, [Parameter(Mandatory)] [scriptblock] $ScriptBlock ) # Modify the environment based on the hashtable and save the original # one for later restoration. $htOrgEnv = @{} foreach ($kv in $Environment.GetEnumerator()) { $htOrgEnv[$kv.Key] = (Get-Item -EA SilentlyContinue "env:$($kv.Key)").Value Set-Item "env:$($kv.Key)" $kv.Value } # Invoke the script block try { & $ScriptBlock } finally { # Restore the original environment. foreach ($kv in $Environment.GetEnumerator()) { # Note: setting an environment var. to $null or '' *removes* it. Set-Item "env:$($kv.Key)" $htOrgEnv[$kv.Key] } } } # Code ported from: # https://source.dot.net/#System.Diagnostics.Process/System/Diagnostics/ProcessStartInfo.cs # https://source.dot.net/#System.Diagnostics.Process/PasteArguments.cs # Licensed to the .NET Foundation under one or more agreements. # The .NET Foundation licenses this file to you under the MIT license. function Append-Argument { param( [Parameter(Mandatory)] [Text.StringBuilder] $Builder, [Parameter(Mandatory)] [AllowEmptyString()] [string] $Arg ) if (-not $Builder.Length -eq 0) { [void]$Builder.Append(' ') } # Parsing rules for non-argv[0] arguments: # - Backslash is a normal character except followed by a quote. # - 2N backslashes followed by a quote ==> N literal backslashes followed by unescaped quote # - 2N+1 backslashes followed by a quote ==> N literal backslashes followed by a literal quote # - Parsing stops at first whitespace outside of quoted region. # - (post 2008 rule): A closing quote followed by another quote ==> literal quote, and parsing remains in quoting mode. if ((-not $Builder.Length -eq 0) -and (ContainsNoWhitespaceOrQuotes $Arg)) { # Simple case - no quoting or changes needed. [void]$Builder.Append($Arg) } else { [void]$Builder.Append('"') $idx = 0 while ($idx -lt $Arg.Length) { $c = $Arg[$idx++] if ($c -eq '\') { $numBackSlash = 1 while (($idx -lt $Arg.Length) -and ($Arg[$idx] -eq '\')) { $idx++ $numBackslash++ } if ($idx -eq $Arg.Length) { # We'll emit an end quote after this so must double the number of backslashes. [void]$Builder.Append('\', $numBackSlash * 2) } elseif ($Arg[$idx] -eq '"') { # Backslashes will be followed by a quote. Must double the number of backslashes. [void]$Builder.Append('\', $numBackSlash * 2 + 1) [void]$Builder.Append('"') $idx++ } else { # Backslash will not be followed by a quote, so emit as normal characters. [void]$Builder.Append('\', $numBackSlash) } continue } if ($c -eq '"') { # Escape the quote so it appears as a literal. This also guarantees that we won't end up generating a closing quote followed # by another quote (which parses differently pre-2008 vs. post-2008.) [void]$Builder.Append('\') [void]$Builder.Append('"') continue } [void]$Builder.Append($c) } [void]$Builder.Append('"') } } function ContainsNoWhitespaceOrQuotes { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $s ) for ($i = 0; $i -lt $s.Length; $i += 1) { $c = $s[$i] if ([char]::IsWhiteSpace($c) -or ($c -eq '"')) { return $False } } $True } function Build-Arguments { param( [Parameter(Mandatory)] [AllowEmptyString()] [AllowNull()] [string[]] $Args ) if ($Args.count -eq 0) { return '' } $Builder = [Text.StringBuilder]::new() $Args | Foreach-Object { Append-Argument $Builder $_ } $Builder.ToString() } function Exec-Process { param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [AllowEmptyString()] [AllowNull()] [string[]] $Args ) if ($Args[0] -eq '--%') { $null, $Args = $Args if ($Args) { $Process = Start-Process $Path -Argument $Args -NoNewWindow -PassThru } else { $Process = Start-Process $Path -NoNewWindow -PassThru } } else { # `Start-Process` simply joins all arguments without escaping and passes it to `ProcessStartInfo.Arguments`; # here we replicate the logic for `ProcessStartInfo.ArgumentList` on .NET 5 and above # See also: https://github.com/PowerShell/PowerShell/issues/14747 # (note that we must nonetheless implement it by ourselves if we support Windows Powershell 5.1) $EscapedArgs = Build-Arguments $Args if ($EscapedArgs) { $Process = Start-Process $Path -ArgumentList $EscapedArgs -NoNewWindow -PassThru } else { $Process = Start-Process $Path -NoNewWindow -PassThru } } # workaround to obtain the exit status properly: https://stackoverflow.com/a/23797762 $hnd = $Process.Handle Wait-Process -Id $Process.Id Exit $Process.ExitCode } $ScriptPath = Resolve-RealPath $PSCommandPath $ScriptRoot = Split-Path -Path $ScriptPath -Parent $CrystalRoot = Split-Path -Path $ScriptRoot -Parent $CrystalDir = "$CrystalRoot\.build" Invoke-WithEnvironment @{ CRYSTAL_PATH = if ($env:CRYSTAL_PATH) { $env:CRYSTAL_PATH } else { "lib;$CrystalRoot\src" } CRYSTAL_HAS_WRAPPER = "true" CRYSTAL = if ($env:CRYSTAL) { $env:CRYSTAL } else { "crystal" } CRYSTAL_CONFIG_LIBRARY_PATH = $env:CRYSTAL_CONFIG_LIBRARY_PATH CRYSTAL_LIBRARY_PATH = $env:CRYSTAL_LIBRARY_PATH } { if (!$env:CRYSTAL_PATH.Contains("$CrystalRoot\src")) { Write-StdErr "CRYSTAL_PATH env variable does not contain $CrystalRoot\src" -ForegroundColor DarkYellow } if (!$env:CRYSTAL_CONFIG_LIBRARY_PATH -or !$env:CRYSTAL_LIBRARY_PATH) { Invoke-WithEnvironment @{ PATH = $env:PATH.Split(';') -ne $ScriptRoot -ne "bin" -join ';' } { $CrystalInstalled = Get-Command "crystal" -CommandType ExternalScript, Application -ErrorAction SilentlyContinue $CrystalInstalledLibraryPath = if ($CrystalInstalled) { crystal env CRYSTAL_LIBRARY_PATH } else { $null } if (!$env:CRYSTAL_CONFIG_LIBRARY_PATH) { $env:CRYSTAL_CONFIG_LIBRARY_PATH = $CrystalInstalledLibraryPath } if (!$env:CRYSTAL_LIBRARY_PATH) { $env:CRYSTAL_LIBRARY_PATH = $CrystalInstalledLibraryPath } } } if (Test-Path -Path "$CrystalDir/crystal.exe" -PathType Leaf) { Write-StdErr "Using compiled compiler at $($CrystalDir.Replace($pwd, "."))\crystal.exe" -ForegroundColor DarkYellow Exec-Process "$CrystalDir/crystal.exe" $CrystalArgs } else { $CrystalCmd = Get-Command $env:CRYSTAL -CommandType ExternalScript, Application -ErrorAction SilentlyContinue if (!$CrystalCmd) { Write-StdErr 'You need to have a crystal executable in your path! or set CRYSTAL env variable' -ForegroundColor Red Exit 1 } else { $CrystalInstalledDir = Split-Path -Path $CrystalCmd.Path -Parent if ($CrystalInstalledDir -eq $ScriptRoot -or $CrystalInstalledDir -eq "bin") { Invoke-WithEnvironment @{ PATH = $env:PATH.Split(';') -ne $ScriptRoot -ne "bin" -join ';' } { Exec-Process $ScriptPath $CrystalArgs } } else { Exec-Process $CrystalCmd.Path $CrystalArgs } } } } ================================================ FILE: devenv.nix ================================================ { pkgs, lib, config, inputs, ... }: { dotenv.enable = true; git-hooks.hooks = { actionlint.enable = true; ameba = { enable = true; name = "Ameba"; entry = "${pkgs.ameba}/bin/ameba --fix"; files = "\\.cr$"; excludes = ["^lib/"]; pass_filenames = true; }; check-toml.enable = true; check-vcs-permalinks.enable = true; circleci.enable = true; crystal.enable = true; makefile_both = { enable = true; name = "Change both Makefile and Makefile.win"; entry = ''${pkgs.runtimeShell} -c 'test "$#" -ne 1 || (echo "Changes only in $@" && false)' --''; files = "^Makefile(\.win)?$"; pass_filenames = true; }; markdownlint.enable = true; shellcheck = { enable = true; excludes = [ ".*\.zsh$" ]; }; typos.enable = true; zizmor.enable = true; }; profiles = { lint.module = { # More expensive hooks that we don't want to execute on every commit all the time git-hooks.hooks = { # reuse always runs on all files in the repo which takes some time. # Violations are very rare, so a longer feedback loop doesn't matter much. reuse.enable = true; }; }; }; } ================================================ FILE: devenv.yaml ================================================ inputs: git-hooks: url: github:cachix/git-hooks.nix nixpkgs: url: github:cachix/devenv-nixpkgs/rolling ================================================ FILE: doc/changelogs/README.md ================================================ # Changelog ## Historical changelogs - [pre-1.0](pre-1.0.md) - [1.0 series](v1.0.md) - [1.1 series](v1.1.md) - [1.2 series](v1.2.md) - [1.3 series](v1.3.md) - [1.4 series](v1.4.md) - [1.5 series](v1.5.md) - [1.6 series](v1.6.md) - [1.7 series](v1.7.md) - [1.8 series](v1.8.md) - [1.9 series](v1.9.md) - [1.10 series](v1.10.md) - [1.11 series](v1.11.md) - [1.12 series](v1.12.md) - [1.13 series](v1.13.md) - [1.14 series](v1.14.md) - [1.15 series](v1.15.md) - [1.16 series](v1.16.md) - [1.17 series](v1.17.md) - [1.18 series](v1.18.md) - [1.19 series](v1.19.md) ================================================ FILE: doc/changelogs/pre-1.0.md ================================================ # Changelog pre 1.0 ## 0.36.1 (2021-02-02) ### Standard library - Fix `Enum.from_value?` for flag enum with non `Int32` base type. ([#10303](https://github.com/crystal-lang/crystal/pull/10303), thanks @straight-shoota) #### Text - Don't raise on `String.new` with `null` pointer and bytesize 0. ([#10308](https://github.com/crystal-lang/crystal/pull/10308), thanks @asterite) #### Collections - Explicitly return a `Hash` in `Hash#dup` and `Hash#clone` (reverts [#9871](https://github.com/crystal-lang/crystal/pull/9871)). ([#10331](https://github.com/crystal-lang/crystal/pull/10331), thanks @straight-shoota) #### Serialization - XML: fix deprecation warning. ([#10335](https://github.com/crystal-lang/crystal/pull/10335), thanks @bcardiff) #### Runtime - Eager load DWARF only if `CRYSTAL_LOAD_DWARF=1`. ([#10326](https://github.com/crystal-lang/crystal/pull/10326), thanks @bcardiff) ### Compiler - **(performance)** Initialize right-away constants in a separate function. ([#10334](https://github.com/crystal-lang/crystal/pull/10334), thanks @asterite) - Fix incorrect casting between different union types. ([#10333](https://github.com/crystal-lang/crystal/pull/10333), thanks @asterite) - Fix a formatting error in the "missing argument" error. ([#10325](https://github.com/crystal-lang/crystal/pull/10325), thanks @BlobCodes) - Fix while condition assignment check for Not. ([#10347](https://github.com/crystal-lang/crystal/pull/10347), thanks @asterite) - Allow operators and setters-like macros names back. ([#10338](https://github.com/crystal-lang/crystal/pull/10338), thanks @asterite) #### Language semantics - Fix type check not considering virtual types. ([#10304](https://github.com/crystal-lang/crystal/pull/10304), thanks @asterite) - Use path lookup when looking up type for auto-cast match. ([#10318](https://github.com/crystal-lang/crystal/pull/10318), thanks @asterite) ## 0.36.0 (2021-01-26) ### Language changes - **(breaking-change)** Reject annotations on ivars defined in base class. ([#9502](https://github.com/crystal-lang/crystal/pull/9502), thanks @waj) - **(breaking-change)** Make `**` be right associative. ([#9684](https://github.com/crystal-lang/crystal/pull/9684), thanks @asterite) #### Macros - **(breaking-change)** Deprecate `TypeNode#has_attribute?` in favor of `#annotation`. ([#9950](https://github.com/crystal-lang/crystal/pull/9950), thanks @HertzDevil) - Support heredoc literal in macro. ([#9467](https://github.com/crystal-lang/crystal/pull/9467), thanks @MakeNowJust) - Support `%Q`, `%i`, `%w`, and `%x` literals in macros. ([#9811](https://github.com/crystal-lang/crystal/pull/9811), thanks @toddsundsted) - Allow executing multi-assignments in macros. ([#9440](https://github.com/crystal-lang/crystal/pull/9440), thanks @MakeNowJust) ### Standard library - **(breaking-change)** Drop deprecated `CRC32`, `Adler32` top-level. ([#9530](https://github.com/crystal-lang/crystal/pull/9530), thanks @bcardiff) - **(breaking-change)** Drop deprecated `Flate`, `Gzip`, `Zip`, `Zlib` top-level. ([#9529](https://github.com/crystal-lang/crystal/pull/9529), thanks @bcardiff) - **(breaking-change)** Drop deprecated `with_color` top-level method. ([#9531](https://github.com/crystal-lang/crystal/pull/9531), thanks @bcardiff) - **(breaking-change)** Make `SemanticVersion` parsing more strict. ([#9868](https://github.com/crystal-lang/crystal/pull/9868), thanks @hugopl) - Respect explicitly provided type vars for `Tuple.new` and `NamedTuple.new`. ([#10047](https://github.com/crystal-lang/crystal/pull/10047), thanks @HertzDevil) - Fix `OptionParser` to handle sub-commands with hyphen. ([#9465](https://github.com/crystal-lang/crystal/pull/9465), thanks @erdnaxeli) - Fix `OptionParser` to not call handler if value is given to none value handler. ([#9603](https://github.com/crystal-lang/crystal/pull/9603), thanks @MakeNowJust) - Make `def_equals` compare first by reference. ([#9650](https://github.com/crystal-lang/crystal/pull/9650), thanks @waj) - Remove unnecessary `def ==(other)` fallbacks. ([#9571](https://github.com/crystal-lang/crystal/pull/9571), thanks @MakeNowJust) - Fix `OptionParser` indentation of option descriptions. ([#10183](https://github.com/crystal-lang/crystal/pull/10183), thanks @wonderix) - Add `#hash` to `Log::Metadata`, `Path`, `SemanticVersion`, `Socket::Address`, `URI::Params`, and `UUID`. ([#10119](https://github.com/crystal-lang/crystal/pull/10119), thanks @straight-shoota) - Refactor several `case` statements with exhaustive `case`/`in`. ([#9656](https://github.com/crystal-lang/crystal/pull/9656), thanks @Sija) - Remove `Kernel` mentions in docs. ([#9549](https://github.com/crystal-lang/crystal/pull/9549), thanks @toddsundsted) - Improve docs for `Object#dup`. ([#10053](https://github.com/crystal-lang/crystal/pull/10053), thanks @straight-shoota) - Fix example codes in multiple places. ([#9818](https://github.com/crystal-lang/crystal/pull/9818), thanks @maiha) - Fix typos, misspelling and styling. ([#9636](https://github.com/crystal-lang/crystal/pull/9636), [#9638](https://github.com/crystal-lang/crystal/pull/9638), [#9561](https://github.com/crystal-lang/crystal/pull/9561), [#9786](https://github.com/crystal-lang/crystal/pull/9786), [#9840](https://github.com/crystal-lang/crystal/pull/9840), [#9844](https://github.com/crystal-lang/crystal/pull/9844), [#9854](https://github.com/crystal-lang/crystal/pull/9854), [#9869](https://github.com/crystal-lang/crystal/pull/9869), [#10068](https://github.com/crystal-lang/crystal/pull/10068), [#10123](https://github.com/crystal-lang/crystal/pull/10123), [#10102](https://github.com/crystal-lang/crystal/pull/10102), [#10116](https://github.com/crystal-lang/crystal/pull/10116), [#10229](https://github.com/crystal-lang/crystal/pull/10229), [#10252](https://github.com/crystal-lang/crystal/pull/10252), thanks @kubo, @m-o-e, @mgomes, @philipp-classen, @dukeraphaelng, @camreeves, @docelic, @ilmanzo, @Sija, @pxeger, @oprypin) #### Macros - Fix documentation for `#[]=` macro methods. ([#10025](https://github.com/crystal-lang/crystal/pull/10025), thanks @HertzDevil) #### Numeric - **(breaking-change)** Move `Complex#exp`, `Complex#log`, etc. to `Math.exp`, `Math.log` overloads. ([#9739](https://github.com/crystal-lang/crystal/pull/9739), thanks @cristian-lsdb) - **(performance)** Use unchecked arithmetics in `Int#times`. ([#9511](https://github.com/crystal-lang/crystal/pull/9511), thanks @waj) - Check for overflow when extending signed integers to unsigned integers. ([#10000](https://github.com/crystal-lang/crystal/pull/10000), thanks @HertzDevil) - Fix `sprintf` for zero left padding a negative number. ([#9725](https://github.com/crystal-lang/crystal/pull/9725), thanks @asterite) - Fix `BigInt#to_64` and `BigInt#hash`. ([#10121](https://github.com/crystal-lang/crystal/pull/10121), thanks @oprypin) - Fix `BigDecimal#to_s` for numbers between `-1` and `0`. ([#9897](https://github.com/crystal-lang/crystal/pull/9897), thanks @dukeraphaelng) - Fix `Number#step`. ([#10130](https://github.com/crystal-lang/crystal/pull/10130), [#10295](https://github.com/crystal-lang/crystal/pull/10295), thanks @straight-shoota, @bcardiff) - Make `Complex` unary plus returns `self`. ([#9719](https://github.com/crystal-lang/crystal/pull/9719), thanks @asterite) - Improve `Int#lcm` and `Int#gcd`. ([#9999](https://github.com/crystal-lang/crystal/pull/9999), thanks @HertzDevil) - Add `Math::TAU`. ([#10179](https://github.com/crystal-lang/crystal/pull/10179), thanks @j8r) - Add wrapped unary negation to unsigned integer types to allow `&- x` expressions. ([#9947](https://github.com/crystal-lang/crystal/pull/9947), thanks @HertzDevil) - Improve documentation of mathematical functions. ([#9994](https://github.com/crystal-lang/crystal/pull/9994), thanks @HertzDevil) #### Text - **(breaking-change)** Fix `String#index` not working well for broken UTF-8 sequences. ([#9713](https://github.com/crystal-lang/crystal/pull/9713), thanks @asterite) - **(performance)** `String`: Don't materialize `Regex` `match[0]` if not needed. ([#9615](https://github.com/crystal-lang/crystal/pull/9615), thanks @asterite) - Fix `String#rindex` default offset for matching empty regex correctly. ([#9690](https://github.com/crystal-lang/crystal/pull/9690), thanks @MakeNowJust) - Add various `String#delete_at` methods. ([#9398](https://github.com/crystal-lang/crystal/pull/9398), thanks @asterite) - Raise if passing `null` Pointer to `String`. ([#9653](https://github.com/crystal-lang/crystal/pull/9653), thanks @jgaskins) - Add `Regex#capture_count`. ([#9746](https://github.com/crystal-lang/crystal/pull/9746), thanks @Sija) - Add `Regex::MatchData#[]` overloading to `Range`. ([#10076](https://github.com/crystal-lang/crystal/pull/10076), thanks @MakeNowJust) - Fix duplicates in `String` documentation. ([#9987](https://github.com/crystal-lang/crystal/pull/9987), thanks @Nicolab) - Add docs for substitution to `Kernel.sprintf`. ([#10227](https://github.com/crystal-lang/crystal/pull/10227), thanks @straight-shoota) #### Collections - **(breaking-change)** Make `Hash#reject!`, `Hash#select!`, and `Hash#compact!` consistent with `Array` and return `self`. ([#9904](https://github.com/crystal-lang/crystal/pull/9904), thanks @caspiano) - **(breaking-change)** Deprecate `Hash#delete_if` in favor of `Hash#reject!`, add `Dequeue#reject!` and `Dequeue#select!`. ([#9878](https://github.com/crystal-lang/crystal/pull/9878), thanks @caspiano) - **(breaking-change)** Change `Set#delete` to return Bool. ([#9590](https://github.com/crystal-lang/crystal/pull/9590), thanks @j8r) - **(breaking-change)** Drop deprecated `Enumerable#grep`. ([#9711](https://github.com/crystal-lang/crystal/pull/9711), thanks @j8r) - **(breaking-change)** Remove `Hash#key_index` . ([#10016](https://github.com/crystal-lang/crystal/pull/10016), thanks @asterite) - **(breaking-change)** Deprecate `StaticArray#[]=(value)` in favor of `StaticArray#fill`. ([#10027](https://github.com/crystal-lang/crystal/pull/10027), thanks @HertzDevil) - **(breaking-change)** Rename `Set#{sub,super}set?` to `{sub,super}set_of?`. ([#10187](https://github.com/crystal-lang/crystal/pull/10187), thanks @straight-shoota) - **(performance)** Optimize `Array#shift` and `Array#unshift`. ([#10081](https://github.com/crystal-lang/crystal/pull/10081), thanks @asterite) - **(performance)** `Array#rotate` optimization for small arrays. ([#8516](https://github.com/crystal-lang/crystal/pull/8516), thanks @wontruefree) - ~~Fix `Hash#dup` and `Hash#clone` to return correct type for subclasses. ([#9871](https://github.com/crystal-lang/crystal/pull/9871), thanks @vlazar)~~ (Reverted by [#10331](https://github.com/crystal-lang/crystal/pull/10331) in 0.36.1) - Fix `Iterator#cons_pair` return type. ([#9788](https://github.com/crystal-lang/crystal/pull/9788), thanks @asterite) - Fix key type restriction of `Hash#merge` block. ([#9495](https://github.com/crystal-lang/crystal/pull/9495), thanks @MakeNowJust) - Fix `Range#step`. ([#10203](https://github.com/crystal-lang/crystal/pull/10203), thanks @straight-shoota) - Let `Range#step` delegate to `begin.step` and allow float based ranges to be stepped. ([#10209](https://github.com/crystal-lang/crystal/pull/10209), thanks @straight-shoota) - Fix `Indexable#join` with `IO`. ([#10152](https://github.com/crystal-lang/crystal/pull/10152), thanks @straight-shoota) - Fix `Flatten` for value-type iterators. ([#10096](https://github.com/crystal-lang/crystal/pull/10096), thanks @f-fr) - Fix `Indexable.range_to_index_and_count` to not raise `IndexError`. ([#10191](https://github.com/crystal-lang/crystal/pull/10191), thanks @straight-shoota) - Handle recursive structures in `def_clone`, `Hash`, `Array`, `Dequeue`. ([#9800](https://github.com/crystal-lang/crystal/pull/9800), thanks @asterite) - Add `BitArray#dup`. ([#9550](https://github.com/crystal-lang/crystal/pull/9550), thanks @andremedeiros) - Allow `Iterator#zip` to take multiple `Iterator` arguments. ([#9944](https://github.com/crystal-lang/crystal/pull/9944), thanks @HertzDevil) - Add `Iterator#with_object(obj, &)`. ([#9956](https://github.com/crystal-lang/crystal/pull/9956), thanks @HertzDevil) - Always clear unused bits of `BitArray`s. ([#10008](https://github.com/crystal-lang/crystal/pull/10008), thanks @HertzDevil) - Update `Enumerable#sum(initial, &)` docs. ([#9860](https://github.com/crystal-lang/crystal/pull/9860), thanks @jage) - Add `Array#unsafe_build`. ([#10092](https://github.com/crystal-lang/crystal/pull/10092), thanks @straight-shoota) - Add identity methods for `#sum` and `#product`. ([#10151](https://github.com/crystal-lang/crystal/pull/10151), thanks @straight-shoota) - Move `combinations`, `permutations`, etc., from `Array` to `Indexable`. ([#10235](https://github.com/crystal-lang/crystal/pull/10235), thanks @wonderix) - Move sampling methods to `Enumerable`. ([#10129](https://github.com/crystal-lang/crystal/pull/10129), thanks @HertzDevil) - Use `Set#add` in `Set#add` documentation. ([#9441](https://github.com/crystal-lang/crystal/pull/9441), thanks @hugopl) - Improve `Hash#values_at` docs. ([#9955](https://github.com/crystal-lang/crystal/pull/9955), thanks @j8r) #### Serialization - **(breaking-change)** Drop deprecated `JSON.mapping`. ([#9527](https://github.com/crystal-lang/crystal/pull/9527), thanks @bcardiff) - **(breaking-change)** Drop deprecated `YAML.mapping`. ([#9526](https://github.com/crystal-lang/crystal/pull/9526), thanks @bcardiff) - Fix flag enum deserialization from `Int64`. ([#10145](https://github.com/crystal-lang/crystal/pull/10145), thanks @straight-shoota) - Add support for selective JSON and YAML serialization. ([#9567](https://github.com/crystal-lang/crystal/pull/9567), thanks @stakach) - YAML: correctly serialize `infinity` and `NaN`. ([#9780](https://github.com/crystal-lang/crystal/pull/9780), thanks @asterite) - YAML: allow using discriminator in contained types. ([#9851](https://github.com/crystal-lang/crystal/pull/9851), thanks @asterite) - Support more literal types in `JSON::Serializable.use_json_discriminator` macro. ([#9222](https://github.com/crystal-lang/crystal/pull/9222), thanks @voximity) - Support more literal types in `YAML::Serializable.use_yaml_discriminator` macro. ([#10149](https://github.com/crystal-lang/crystal/pull/10149), thanks @straight-shoota) - Add `JSON` serialization to big number types. ([#9898](https://github.com/crystal-lang/crystal/pull/9898), [#10054](https://github.com/crystal-lang/crystal/pull/10054), thanks @dukeraphaelng, @Sija) - Handle namespaced defaults in `JSON::Serializable` and `YAML::Serializable`. ([#9733](https://github.com/crystal-lang/crystal/pull/9733), thanks @jgaskins) - Standardize YAML error location. ([#9273](https://github.com/crystal-lang/crystal/pull/9273), thanks @straight-shoota) - Update `YAML::Field(converter)` argument docs. ([#9557](https://github.com/crystal-lang/crystal/pull/9557), thanks @dscottboggs) - Use `content` instead of `value` when inspect `XML::Attribute`. ([#9592](https://github.com/crystal-lang/crystal/pull/9592), thanks @asterite) - Let `JSON::PullParser#on_key` yield self and return value. ([#10028](https://github.com/crystal-lang/crystal/pull/10028), thanks @straight-shoota) - Cleanup `YAML`/`JSON` `Any#dig` methods. ([#9415](https://github.com/crystal-lang/crystal/pull/9415), thanks @j8r) - Document `JSON::PullParser`. ([#9983](https://github.com/crystal-lang/crystal/pull/9983), thanks @erdnaxeli) - Clarify Serialization Converter requirements and examples. ([#10202](https://github.com/crystal-lang/crystal/pull/10202), thanks @Daniel-Worrall) #### Time - **(breaking-change)** Drop deprecated `Time::Span.new` variants. ([#10051](https://github.com/crystal-lang/crystal/pull/10051), thanks @Sija) - **(breaking-change)** Deprecate `Time::Span#duration`, use `Time::Span#abs`. ([#10144](https://github.com/crystal-lang/crystal/pull/10144), thanks @straight-shoota) - Add `%Z` time format directive. ([#10141](https://github.com/crystal-lang/crystal/pull/10141), thanks @straight-shoota) - Improve handling edge cases for `Time::Location#load`. ([#10140](https://github.com/crystal-lang/crystal/pull/10140), thanks @straight-shoota) - Enable pending specs. ([#10093](https://github.com/crystal-lang/crystal/pull/10093), thanks @straight-shoota) - Improve `Time::Span` arithmetic specs. ([#10143](https://github.com/crystal-lang/crystal/pull/10143), thanks @straight-shoota) #### Files - **(breaking-change)** Make `File.size` and `FileInfo#size` be `Int64` instead of `UInt64`. ([#10015](https://github.com/crystal-lang/crystal/pull/10015), thanks @asterite) - **(breaking-change)** Fix `FileUtils.cp_r` when destination is a directory. ([#10180](https://github.com/crystal-lang/crystal/pull/10180), thanks @wonderix) - Enable large-file support on i386-linux-gnu. ([#9478](https://github.com/crystal-lang/crystal/pull/9478), thanks @kubo) - Fix glob not following symdir directories. ([#9910](https://github.com/crystal-lang/crystal/pull/9910), thanks @straight-shoota) - Windows: allow creating symlinks without admin rights. ([#9767](https://github.com/crystal-lang/crystal/pull/9767), thanks @oprypin) - Windows: allow touching directories. ([#10284](https://github.com/crystal-lang/crystal/pull/10284), thanks @straight-shoota) - Fix `Dir.glob` when `readdir` doesn't report file type. ([#9877](https://github.com/crystal-lang/crystal/pull/9877), thanks @straight-shoota) - Add `Path#stem`. ([#10037](https://github.com/crystal-lang/crystal/pull/10037), thanks @straight-shoota) - Move `File#fsync`, `File#flock_exclusive`, `File#flock_shared`, and `File#flock_unlock` methods to `IO::FileDescriptor`. ([#9794](https://github.com/crystal-lang/crystal/pull/9794), thanks @naqvis) - Call `IO#flush` on builder finish methods. ([#9321](https://github.com/crystal-lang/crystal/pull/9321), thanks @straight-shoota) - Support using `Path` in `MIME` and `File::Error` APIs. ([#10034](https://github.com/crystal-lang/crystal/pull/10034), thanks @Blacksmoke16) - Windows: enable `FileUtils` specs. ([#9902](https://github.com/crystal-lang/crystal/pull/9902), thanks @oprypin) #### Networking - **(breaking-change)** Rename `HTTP::Params` to `URI::Params`. ([#10098](https://github.com/crystal-lang/crystal/pull/10098), thanks @straight-shoota) - **(breaking-change)** Rename `URI#full_path` to `URI#request_target`. ([#10099](https://github.com/crystal-lang/crystal/pull/10099), thanks @straight-shoota) - **(breaking-change)** `URI::Params#[]=` replaces all values. ([#9605](https://github.com/crystal-lang/crystal/pull/9605), thanks @asterite) - Fix type of `HTTP::Server::Response#closed?` to `Bool`. ([#9489](https://github.com/crystal-lang/crystal/pull/9489), thanks @straight-shoota) - Fix `Socket#accept` to obey `read_timeout`. ([#9538](https://github.com/crystal-lang/crystal/pull/9538), thanks @waj) - Fix `Socket` to allow datagram over unix sockets. ([#9838](https://github.com/crystal-lang/crystal/pull/9838), thanks @bcardiff) - Fix `HTTP::Headers#==` and `HTTP::Headers#hash`. ([#10186](https://github.com/crystal-lang/crystal/pull/10186), thanks @straight-shoota) - Make `HTTP::StaticFileHandler` serve pre-gzipped content. ([#9626](https://github.com/crystal-lang/crystal/pull/9626), thanks @waj) - Delete `Content-Encoding` and `Content-Length` headers after decompression in `HTTP::Client::Response`. ([#5212](https://github.com/crystal-lang/crystal/pull/5212), thanks @maiha) - Delay setup of `HTTP::CompressHandler` until content is written. ([#9625](https://github.com/crystal-lang/crystal/pull/9625), thanks @waj) - Allow `HTTP::Client` to work with any IO. ([#9543](https://github.com/crystal-lang/crystal/pull/9543), thanks @waj) - Make `HTTP::Server` don't override `content-length` if already set. ([#9726](https://github.com/crystal-lang/crystal/pull/9726), thanks @asterite) - Do not share underlying hash between `URI::Param`s. ([#9641](https://github.com/crystal-lang/crystal/pull/9641), thanks @jgaskins) - Add `HTTP::Cookie::SameSite::None`. ([#9262](https://github.com/crystal-lang/crystal/pull/9262), thanks @j8r) - Add `HTTP::Client` logging and basic instrumentation. ([#9756](https://github.com/crystal-lang/crystal/pull/9756), thanks @bcardiff) - Add `HTTP::Request#hostname`+ utils. ([#10029](https://github.com/crystal-lang/crystal/pull/10029), thanks @straight-shoota) - Add `URI#authority`. ([#10100](https://github.com/crystal-lang/crystal/pull/10100), thanks @straight-shoota) - Add `Socket::IPAddress#private?`. ([#9517](https://github.com/crystal-lang/crystal/pull/9517), thanks @jgillich) - Make `Socket::IpAddress` a bit more type-friendly. ([#9528](https://github.com/crystal-lang/crystal/pull/9528), thanks @asterite) - Make specs pass in non-IPv6 environments. ([#9438](https://github.com/crystal-lang/crystal/pull/9438), thanks @jhass) - Make specs pending instead of failing in no multi-cast environments. ([#9566](https://github.com/crystal-lang/crystal/pull/9566), thanks @jhass) - Remove invalid optimization on `Encoding`. ([#9724](https://github.com/crystal-lang/crystal/pull/9724), thanks @asterite) - Drop `RemoteAddressType` private alias. ([#9777](https://github.com/crystal-lang/crystal/pull/9777), thanks @bcardiff) - Add documentation for `HTTP::WebSocket`. ([#9761](https://github.com/crystal-lang/crystal/pull/9761), [#9778](https://github.com/crystal-lang/crystal/pull/9778), thanks @ibraheemdev, @bcardiff) - Fix `HTTP` docs. ([#9612](https://github.com/crystal-lang/crystal/pull/9612), [#9627](https://github.com/crystal-lang/crystal/pull/9627), [#9717](https://github.com/crystal-lang/crystal/pull/9717), thanks @RX14, @asterite, @3n-k1) - Fix reference to TCP protocol in docs. ([#9457](https://github.com/crystal-lang/crystal/pull/9457), thanks @dprobinson) #### Logging - **(breaking-change)** Drop deprecated `Logger`. ([#9525](https://github.com/crystal-lang/crystal/pull/9525), thanks @bcardiff) - **(performance)** Add logging dispatcher to defer entry dispatch from current fiber. ([#9432](https://github.com/crystal-lang/crystal/pull/9432), thanks @waj) - Take timestamp as an argument in `Log::Entry` initializer. ([#9570](https://github.com/crystal-lang/crystal/pull/9570), thanks @Sija) - Improve docs regarding `Log.setup`. ([#9497](https://github.com/crystal-lang/crystal/pull/9497), [#9559](https://github.com/crystal-lang/crystal/pull/9559), thanks @caspiano, @jjlorenzo) #### Crypto - **(security)** Fix `"force-peer"` `verify_mode` setup. ([#9668](https://github.com/crystal-lang/crystal/pull/9668), thanks @PhilAtWysdom) - **(security)** Force secure renegotiation on server to prevent Secure Client-Initiated Renegotiation vulnerability attack. ([#9815](https://github.com/crystal-lang/crystal/pull/9815), thanks @bcardiff) - **(breaking-change)** Refactor `Digest` and introduce `Digest::MD5`, `Digest::SHA1`, `Digest::SHA256`, `Digest::SHA512` backed by openssl. ([#9864](https://github.com/crystal-lang/crystal/pull/9864), thanks @bcardiff) - Fix overflows in MD5 and SHA1. ([#9781](https://github.com/crystal-lang/crystal/pull/9781), thanks @bcardiff) - Add `OpenSSL::SSL::Context#set_modern_ciphers` and related methods to set ciphers and cipher suites in a more portable fashion. ([#9814](https://github.com/crystal-lang/crystal/pull/9814), [#10298](https://github.com/crystal-lang/crystal/pull/10298), thanks @bcardiff) - Add `OpenSSL::SSL::Context#security_level`. ([#9831](https://github.com/crystal-lang/crystal/pull/9831), thanks @bcardiff) - `OpenSSL::digest` add require for `OpenSSL::Error`. ([#10173](https://github.com/crystal-lang/crystal/pull/10173), thanks @wonderix) #### Concurrency - **(breaking-change)** Hide Channel internal implementation methods. ([#9564](https://github.com/crystal-lang/crystal/pull/9564), thanks @j8r) - `Channel#close` returns `true` unless the channel was already closed. ([#9443](https://github.com/crystal-lang/crystal/pull/9443), thanks @waj) - Support splat expressions inside `spawn` macro. ([#10234](https://github.com/crystal-lang/crystal/pull/10234), thanks @HertzDevil) - Remove incorrect note about negative timeout not triggering. ([#10131](https://github.com/crystal-lang/crystal/pull/10131), thanks @straight-shoota) #### System - Fix `Process.find_executable` to check the found path is executable and add Windows support. ([#9365](https://github.com/crystal-lang/crystal/pull/9365), thanks @oprypin) - Add `Process.parse_arguments` and fix `CRYSTAL_OPTS` parsing. ([#9518](https://github.com/crystal-lang/crystal/pull/9518), thanks @MakeNowJust) - Port to NetBSD. ([#9360](https://github.com/crystal-lang/crystal/pull/9360), thanks @niacat) - Add note about raising `IO::Error` to `Process` methods. ([#9894](https://github.com/crystal-lang/crystal/pull/9894), thanks @straight-shoota) - Handle errors in `User`/`Group` `from_name?`/`from_id?` as not found. ([#10182](https://github.com/crystal-lang/crystal/pull/10182), thanks @wonderix) - define the `SC_PAGESIZE` constant on more platforms. ([#9821](https://github.com/crystal-lang/crystal/pull/9821), thanks @carlhoerberg) #### Runtime - Fix bug with passing many args then a struct in Win64 C lib ABI. ([#9520](https://github.com/crystal-lang/crystal/pull/9520), thanks @oprypin) - Fix C ABI for AArch64. ([#9430](https://github.com/crystal-lang/crystal/pull/9430), thanks @jhass) - Disable LLVM Global Isel. ([#9401](https://github.com/crystal-lang/crystal/pull/9401), [#9562](https://github.com/crystal-lang/crystal/pull/9562), thanks @jhass, @bcardiff) - Print original exception after failing to raise it. ([#9220](https://github.com/crystal-lang/crystal/pull/9220), thanks @jhass) - Use Dwarf information on `Exception::CallStack.print_frame` and crash stacktraces. ([#9792](https://github.com/crystal-lang/crystal/pull/9792), [#9852](https://github.com/crystal-lang/crystal/pull/9852), thanks @bcardiff) - `MachO`: Handle missing `LC_UUID`. ([#9706](https://github.com/crystal-lang/crystal/pull/9706), thanks @bcardiff) - Allow `WeakRef` to compile with `-Dgc_none`. ([#9806](https://github.com/crystal-lang/crystal/pull/9806), thanks @bcardiff) - Fix example in `Crystal.main` docs. ([#9736](https://github.com/crystal-lang/crystal/pull/9736), thanks @hugopl) - Add a C ABI spec for accepting a large struct - failing on Win32, AArch64. ([#9534](https://github.com/crystal-lang/crystal/pull/9534), thanks @oprypin) - Don't relativize paths outside of current directory in backtrace. ([#10177](https://github.com/crystal-lang/crystal/pull/10177), thanks @Sija) - Avoid loading DWARF if env var `CRYSTAL_LOAD_DWARF=0`. ([#10261](https://github.com/crystal-lang/crystal/pull/10261), thanks @bcardiff) - Fix DWARF loading in FreeBSD. ([#10259](https://github.com/crystal-lang/crystal/pull/10259), thanks @bcardiff) - Print unhandled exceptions from main routine with `#inspect_with_backtrace`. ([#10086](https://github.com/crystal-lang/crystal/pull/10086), thanks @straight-shoota) #### Spec - **(breaking-change)** Add support for custom failure messages in expectations. ([#10127](https://github.com/crystal-lang/crystal/pull/10127), [#10289](https://github.com/crystal-lang/crystal/pull/10289), thanks @Fryguy, @straight-shoota) - Allow absolute file paths in `crystal spec` CLI. ([#9951](https://github.com/crystal-lang/crystal/pull/9951), thanks @KevinSjoberg) - Allow `--link-flags` to be used. ([#6243](https://github.com/crystal-lang/crystal/pull/6243), thanks @bcardiff) - Improve duration display in `spec --profile`. ([#10044](https://github.com/crystal-lang/crystal/pull/10044), thanks @straight-shoota) - Add exception handler in spec `at_exit`. ([#10106](https://github.com/crystal-lang/crystal/pull/10106), thanks @straight-shoota) ### Compiler - **(performance)** Don't use init check for constants that are declared before read. ([#9801](https://github.com/crystal-lang/crystal/pull/9801), thanks @asterite) - **(performance)** Don't use init check for class vars initialized before read. ([#9995](https://github.com/crystal-lang/crystal/pull/9995), thanks @asterite) - **(performance)** Don't use init flag for string constants. ([#9808](https://github.com/crystal-lang/crystal/pull/9808), thanks @asterite) - Run side effects for class var with constant initializer. ([#10010](https://github.com/crystal-lang/crystal/pull/10010), thanks @asterite) - Fix `VaList` and disable `va_arg` for AArch64. ([#9422](https://github.com/crystal-lang/crystal/pull/9422), thanks @jhass) - Fix cache corrupted when compilation is cancelled. ([#9558](https://github.com/crystal-lang/crystal/pull/9558), thanks @waj) - Consider `select` as an opening keyword in macros. ([#9624](https://github.com/crystal-lang/crystal/pull/9624), thanks @asterite) - Use function attribute `frame-pointer`. ([#9361](https://github.com/crystal-lang/crystal/pull/9361), thanks @kubo39) - Make missing `__crystal_raise_overflow` error more clear. ([#9686](https://github.com/crystal-lang/crystal/pull/9686), thanks @3n-k1) - Forbid calls with both block arg and block. ([#10026](https://github.com/crystal-lang/crystal/pull/10026), thanks @HertzDevil) - Add method name to frozen type error. ([#10057](https://github.com/crystal-lang/crystal/pull/10057), thanks @straight-shoota) - Use file lock to avoid clashes between compilations. ([#10050](https://github.com/crystal-lang/crystal/pull/10050), thanks @asterite) - Add a couple of missing end locations to some nodes. ([#10012](https://github.com/crystal-lang/crystal/pull/10012), thanks @asterite) - Don't visit enum member expanded by macro twice. ([#10105](https://github.com/crystal-lang/crystal/pull/10105), thanks @asterite) - Fix crash when matching arguments against splat restriction after positional parameters. ([#10172](https://github.com/crystal-lang/crystal/pull/10172), thanks @HertzDevil) - Fix parsing of `do end` blocks inside parenthesis. ([#10189](https://github.com/crystal-lang/crystal/pull/10189), [#10207](https://github.com/crystal-lang/crystal/pull/10207), thanks @straight-shoota, @Sija) - Fix regex parsing after then in `case/when`. ([#10274](https://github.com/crystal-lang/crystal/pull/10274), thanks @asterite) - Fix error message for non-exhaustive case statements of 3 or more `Bool`/`Enum` values. ([#10194](https://github.com/crystal-lang/crystal/pull/10194), thanks @HertzDevil) - Forbid reopening generic types with different type var splats. ([#10167](https://github.com/crystal-lang/crystal/pull/10167), thanks @HertzDevil) - Apply stricter checks to macro names. ([#10069](https://github.com/crystal-lang/crystal/pull/10069), thanks @HertzDevil) - Reword error message when including/inheriting generic type without type vars. ([#10206](https://github.com/crystal-lang/crystal/pull/10206), thanks @HertzDevil) - Print a message pointing to the online playground if compiled without it. ([#9622](https://github.com/crystal-lang/crystal/pull/9622), thanks @deiv) - Handle typedef type restriction against alias type correctly. ([#9490](https://github.com/crystal-lang/crystal/pull/9490), thanks @MakeNowJust) - Initial support LLVM 11.0 with known issue regarding optimizations [#10220](https://github.com/crystal-lang/crystal/issues/10220). ([#9829](https://github.com/crystal-lang/crystal/pull/9829), [#10293](https://github.com/crystal-lang/crystal/pull/10293), thanks @bcardiff) - Add support for `--mcpu native`. ([#10264](https://github.com/crystal-lang/crystal/pull/10264), [#10276](https://github.com/crystal-lang/crystal/pull/10276), thanks @BlobCodes, @bcardiff) - Fix `Process.run` uses in compiler to handle exec failure. ([#9893](https://github.com/crystal-lang/crystal/pull/9893), [#9911](https://github.com/crystal-lang/crystal/pull/9911), [#9913](https://github.com/crystal-lang/crystal/pull/9913), thanks @straight-shoota, @bcardiff, @oprypin) - Fix `Command#report_warnings` to gracefully handle missing `Compiler#program`. ([#9866](https://github.com/crystal-lang/crystal/pull/9866), thanks @straight-shoota) - Add `Program#host_compiler`. ([#9920](https://github.com/crystal-lang/crystal/pull/9920), thanks @straight-shoota) - Add `Crystal::Path#name_size` implementation. ([#9380](https://github.com/crystal-lang/crystal/pull/9380), thanks @straight-shoota) - Refactor helper methods in `call_error.cr`. ([#9376](https://github.com/crystal-lang/crystal/pull/9376), thanks @straight-shoota) - Delegate def error location to implementing type. ([#10159](https://github.com/crystal-lang/crystal/pull/10159), thanks @straight-shoota) - Refactor `Crystal::Exception` to `Crystal::CodeError`. ([#10197](https://github.com/crystal-lang/crystal/pull/10197), thanks @straight-shoota) - Refactor `check_single_def_error_message`. ([#10196](https://github.com/crystal-lang/crystal/pull/10196), thanks @straight-shoota) - Code clean-ups. ([#9468](https://github.com/crystal-lang/crystal/pull/9468), thanks @MakeNowJust) - Refactors for compiler specs. ([#9379](https://github.com/crystal-lang/crystal/pull/9379), thanks @straight-shoota) - Windows CI: Fix and enable compiler specs. ([#9348](https://github.com/crystal-lang/crystal/pull/9348), [#9560](https://github.com/crystal-lang/crystal/pull/9560), thanks @oprypin) #### Language semantics - **(breaking-change)** Handle union restrictions with free vars properly. ([#10267](https://github.com/crystal-lang/crystal/pull/10267), thanks @HertzDevil) - **(breaking-change)** Disallow keywords as block argument name. ([#9704](https://github.com/crystal-lang/crystal/pull/9704), thanks @asterite) - **(breaking-change)** Fix `a-b -c` incorrectly parsed as `a - (b - c)`. ([#9652](https://github.com/crystal-lang/crystal/pull/9652), [#9884](https://github.com/crystal-lang/crystal/pull/9884), thanks @asterite, @bcardiff) - **(breaking-change)** Check abstract def implementations with splats, default values and keyword arguments. ([#9585](https://github.com/crystal-lang/crystal/pull/9585), thanks @waj) - **(breaking-change)** Make abstract def return type warning an error. ([#9810](https://github.com/crystal-lang/crystal/pull/9810), thanks @bcardiff) - **(breaking-change)** Error when abstract def implementation adds a type restriction. ([#9634](https://github.com/crystal-lang/crystal/pull/9634), thanks @waj) - **(breaking-change)** Don't interpret Proc typedefs as aliases. ([#10254](https://github.com/crystal-lang/crystal/pull/10254), thanks @HertzDevil) - **(breaking-change)** Remove the special logic of union of pointer and `nil`. ([#9872](https://github.com/crystal-lang/crystal/pull/9872), thanks @asterite) - Check abstract def implementations with double splats. ([#9633](https://github.com/crystal-lang/crystal/pull/9633), thanks @waj) - Make inherited hook work through generic instances. ([#9701](https://github.com/crystal-lang/crystal/pull/9701), thanks @asterite) - Attach doc comment to annotation in macro expansion. ([#9630](https://github.com/crystal-lang/crystal/pull/9630), thanks @MakeNowJust) - Marks else branch of exhaustive case as unreachable, improving resulting type. ([#9659](https://github.com/crystal-lang/crystal/pull/9659), thanks @Sija) - Make `Pointer(T)#value=` stricter for generic arguments. ([#10224](https://github.com/crystal-lang/crystal/pull/10224), thanks @asterite) - Extend type filtering of conditional clauses to arbitrary logical connectives. ([#10147](https://github.com/crystal-lang/crystal/pull/10147), thanks @HertzDevil) - Support NamedTuple instance restrictions in redefinition checks. ([#10245](https://github.com/crystal-lang/crystal/pull/10245), thanks @HertzDevil) - Respect block arg restriction when given block has a splat parameter. ([#10242](https://github.com/crystal-lang/crystal/pull/10242), thanks @HertzDevil) - Make overloads without double splat more specialized than overloads with one. ([#10185](https://github.com/crystal-lang/crystal/pull/10185), thanks @HertzDevil) - Support type splats inside explicit Unions in type restrictions. ([#10174](https://github.com/crystal-lang/crystal/pull/10174), thanks @HertzDevil) - Fix splats on generic arguments. ([#9859](https://github.com/crystal-lang/crystal/pull/9859), thanks @asterite) - Correctly compute line number after macro escape. ([#9858](https://github.com/crystal-lang/crystal/pull/9858), thanks @asterite) - Fix bug for C structs assigned to a type. ([#9743](https://github.com/crystal-lang/crystal/pull/9743), thanks @matthewmcgarvey) - Promote C variadic args as needed. ([#9747](https://github.com/crystal-lang/crystal/pull/9747), thanks @asterite) - Fix parsing of `def self./` and `def self.%`. ([#9721](https://github.com/crystal-lang/crystal/pull/9721), thanks @asterite) - Fix `ASTNode#to_s` for parenthesized expression in block. ([#9629](https://github.com/crystal-lang/crystal/pull/9629), thanks @MakeNowJust) - Don't form a closure on `typeof(@ivar)`. ([#9723](https://github.com/crystal-lang/crystal/pull/9723), thanks @asterite) - Add a few missing `expanded.transform self`. ([#9506](https://github.com/crystal-lang/crystal/pull/9506), thanks @asterite) - Treat `super` as special only if it doesn't have a receiver (i.e.: allow `super` user defined methods). ([#10011](https://github.com/crystal-lang/crystal/pull/10011), thanks @asterite) - Implement auto-casting in a better way. ([#9501](https://github.com/crystal-lang/crystal/pull/9501), thanks @asterite) - Try literal type first when autocasting to unions types. ([#9610](https://github.com/crystal-lang/crystal/pull/9610), thanks @asterite) - Correctly pass named arguments for `previous_def` and `super`. ([#9834](https://github.com/crystal-lang/crystal/pull/9834), thanks @asterite) - Turn proc pointer into proc literal in some cases to closure needed variables. ([#9824](https://github.com/crystal-lang/crystal/pull/9824), thanks @asterite) - Fix proc of self causing multi-dispatch. ([#9972](https://github.com/crystal-lang/crystal/pull/9972), thanks @asterite) - Fixes and improvements to closured variables. ([#9986](https://github.com/crystal-lang/crystal/pull/9986), thanks @asterite) - Don't merge proc types but allow assigning them if they are compatible. ([#9971](https://github.com/crystal-lang/crystal/pull/9971), thanks @asterite) - Reset nilable vars inside block method. ([#10091](https://github.com/crystal-lang/crystal/pull/10091), thanks @asterite) - Reset free vars before attempting each overload match. ([#10271](https://github.com/crystal-lang/crystal/pull/10271), thanks @HertzDevil) - Let `offsetof` support `Tuples`. ([#10218](https://github.com/crystal-lang/crystal/pull/10218), thanks @hugopl) ### Tools - Fetch git config correctly. ([#9640](https://github.com/crystal-lang/crystal/pull/9640), thanks @dorianmariefr) #### Formatter - Avoid adding a newline after comment before end. ([#9722](https://github.com/crystal-lang/crystal/pull/9722), thanks @asterite) - Apply string pieces combination even if heredoc has no indent. ([#9475](https://github.com/crystal-lang/crystal/pull/9475), thanks @MakeNowJust) - Correctly format named arguments like `foo:bar`. ([#9740](https://github.com/crystal-lang/crystal/pull/9740), thanks @asterite) - Handle comment before do in a separate line. ([#9762](https://github.com/crystal-lang/crystal/pull/9762), thanks @asterite) - Fix indent for the first comment of `select when`/`else`. ([#10002](https://github.com/crystal-lang/crystal/pull/10002), thanks @MakeNowJust) - Reduce redundant newlines at end of `begin ... end`. ([#9741](https://github.com/crystal-lang/crystal/pull/9741), thanks @MakeNowJust) - Let formatter normalize crystal language tag for code blocks in doc comments. ([#10156](https://github.com/crystal-lang/crystal/pull/10156), thanks @straight-shoota) - Fix indentation of trailing comma in call with a block. ([#10223](https://github.com/crystal-lang/crystal/pull/10223), thanks @MakeNowJust) #### Doc generator - Linkification: refactor, fix edge cases and add specs. ([#9817](https://github.com/crystal-lang/crystal/pull/9817), thanks @oprypin) - Exclude types from docs who are in nodoc namespaces. ([#9819](https://github.com/crystal-lang/crystal/pull/9819), thanks @Blacksmoke16) - Fix link generation for lib type reference. ([#9931](https://github.com/crystal-lang/crystal/pull/9931), thanks @straight-shoota) - Correctly render underscores in code blocks. ([#9822](https://github.com/crystal-lang/crystal/pull/9822), thanks @Blacksmoke16) - Fix some HTML in docs generator. ([#9918](https://github.com/crystal-lang/crystal/pull/9918), thanks @straight-shoota) - Correctly handle broken source code on syntax highlighting. ([#9416](https://github.com/crystal-lang/crystal/pull/9416), thanks @MakeNowJust) - Re-introduce canonical URL for docs generator. ([#9917](https://github.com/crystal-lang/crystal/pull/9917), thanks @straight-shoota) - Expose `"location"` and `"args_html"` in doc JSON. ([#10122](https://github.com/crystal-lang/crystal/pull/10122), [#10200](https://github.com/crystal-lang/crystal/pull/10200), thanks @oprypin) - Expose `"aliased_html"` in doc JSON, make `"aliased"` field nullable. ([#10117](https://github.com/crystal-lang/crystal/pull/10117), thanks @oprypin) - Support linking to section headings in same tab. ([#9826](https://github.com/crystal-lang/crystal/pull/9826), thanks @Blacksmoke16) - Do not highlight `undef` as a keyword, it's not. ([#10216](https://github.com/crystal-lang/crystal/pull/10216), thanks @rhysd) ### Others - CI improvements and housekeeping. ([#9507](https://github.com/crystal-lang/crystal/pull/9507), [#9513](https://github.com/crystal-lang/crystal/pull/9513), [#9512](https://github.com/crystal-lang/crystal/pull/9512), [#9515](https://github.com/crystal-lang/crystal/pull/9515), [#9514](https://github.com/crystal-lang/crystal/pull/9514), [#9609](https://github.com/crystal-lang/crystal/pull/9609), [#9642](https://github.com/crystal-lang/crystal/pull/9642), [#9758](https://github.com/crystal-lang/crystal/pull/9758), [#9763](https://github.com/crystal-lang/crystal/pull/9763), [#9850](https://github.com/crystal-lang/crystal/pull/9850), [#9906](https://github.com/crystal-lang/crystal/pull/9906), [#9907](https://github.com/crystal-lang/crystal/pull/9907), [#9912](https://github.com/crystal-lang/crystal/pull/9912), [#10078](https://github.com/crystal-lang/crystal/pull/10078), [#10217](https://github.com/crystal-lang/crystal/pull/10217), [#10255](https://github.com/crystal-lang/crystal/pull/10255), thanks @jhass, @bcardiff, @waj, @oprypin, @j8r, @Sija) - Add timeout to individual specs on multi-threading. ([#9865](https://github.com/crystal-lang/crystal/pull/9865), thanks @bcardiff) - Initial AArch64 CI. ([#9508](https://github.com/crystal-lang/crystal/pull/9508), [#9582](https://github.com/crystal-lang/crystal/pull/9582), thanks @jhass, @waj) - Update distribution-scripts and use LLVM 10 on Linux packages. ([#9710](https://github.com/crystal-lang/crystal/pull/9710), thanks @bcardiff) - Update distribution-scripts and publish nightly packages to bintray. ([#9663](https://github.com/crystal-lang/crystal/pull/9663), thanks @bcardiff) - Update distribution-scripts to use Shards v0.13.0. ([#10280](https://github.com/crystal-lang/crystal/pull/10280), thanks @bcardiff) - Initial Nix development environment. Use Nix for OSX CI instead of homebrew. ([#9727](https://github.com/crystal-lang/crystal/pull/9727), [#9776](https://github.com/crystal-lang/crystal/pull/9776), thanks @bcardiff) - Prevent recursive call in `bin/crystal` wrapper. ([#9505](https://github.com/crystal-lang/crystal/pull/9505), thanks @jhass) - Allow overriding `CRYSTAL_PATH` in `bin/crystal` wrapper . ([#9632](https://github.com/crystal-lang/crystal/pull/9632), thanks @bcardiff) - Makefile: support changing the current crystal via env var and argument. ([#9471](https://github.com/crystal-lang/crystal/pull/9471), thanks @bcardiff) - Makefile: improve supported LLVM versions message. ([#10221](https://github.com/crystal-lang/crystal/pull/10221), [#10269](https://github.com/crystal-lang/crystal/pull/10269), thanks @rdp, @straight-shoota) - Update CONTRIBUTING.md. ([#9448](https://github.com/crystal-lang/crystal/pull/9448), [#10249](https://github.com/crystal-lang/crystal/pull/10249), [#10250](https://github.com/crystal-lang/crystal/pull/10250), thanks @wontruefree, @sanks64, @straight-shoota) - Refactor `RedBlackTree` sample to use an enum instead of symbols. ([#10233](https://github.com/crystal-lang/crystal/pull/10233), thanks @Sija) - Add security policy. ([#9984](https://github.com/crystal-lang/crystal/pull/9984), thanks @straight-shoota) - Use `name: nightly` in docs-versions.sh for HEAD. ([#9915](https://github.com/crystal-lang/crystal/pull/9915), thanks @straight-shoota) - Use canonical base url for generating docs. ([#10007](https://github.com/crystal-lang/crystal/pull/10007), thanks @straight-shoota) - Remove Vagrantfile. ([#10033](https://github.com/crystal-lang/crystal/pull/10033), thanks @straight-shoota) - Update NOTICE's copyright year to 2021. ([#10166](https://github.com/crystal-lang/crystal/pull/10166), thanks @matiasgarciaisaia) ## 0.35.1 (2020-06-19) ### Standard library #### Collections - Remove `Hash#each` type restriction to allow working with splats. ([#9456](https://github.com/crystal-lang/crystal/pull/9456), thanks @bcardiff) #### Networking - Revert `IO#write` changes in 0.35.0 and let it return Nil. ([#9469](https://github.com/crystal-lang/crystal/pull/9469), thanks @bcardiff) - Avoid leaking logging context in HTTP request handlers. ([#9494](https://github.com/crystal-lang/crystal/pull/9494), thanks @Blacksmoke16) #### Crypto - Use less strict cipher compatibility for OpenSSL client context. ([#9459](https://github.com/crystal-lang/crystal/pull/9459), thanks @straight-shoota) - Fix `Digest::Base` block argument type restrictions. ([#9500](https://github.com/crystal-lang/crystal/pull/9500), thanks @straight-shoota) #### Logging - Fix `Log.context.set` docs for hash based data. ([#9470](https://github.com/crystal-lang/crystal/pull/9470), thanks @bcardiff) ### Compiler - Show warnings even if there are errors. ([#9461](https://github.com/crystal-lang/crystal/pull/9461), thanks @asterite) - Fix parsing of `{foo: X, typeof: Y}` type. ([#9453](https://github.com/crystal-lang/crystal/pull/9453), thanks @MakeNowJust) - Fix parsing of proc in hash `of` key type. ([#9458](https://github.com/crystal-lang/crystal/pull/9458), thanks @MakeNowJust) - Revert debug level information changes in specs to fix 32 bits builds. ([#9466](https://github.com/crystal-lang/crystal/pull/9466), thanks @bcardiff) ### Others - CI improvements and housekeeping. ([#9455](https://github.com/crystal-lang/crystal/pull/9455), thanks @bcardiff) - Code formatting. ([#9482](https://github.com/crystal-lang/crystal/pull/9482), thanks @MakeNowJust) ## 0.35.0 (2020-06-09) ### Language changes - **(breaking-change)** Let `case when` be non-exhaustive, introduce `case in` as exhaustive. ([#9258](https://github.com/crystal-lang/crystal/pull/9258), [#9045](https://github.com/crystal-lang/crystal/pull/9045), thanks @asterite) - Allow `->@ivar.foo` and `->@@cvar.foo` expressions. ([#9268](https://github.com/crystal-lang/crystal/pull/9268), thanks @MakeNowJust) #### Macros - Allow executing OpAssign (`+=`, `||=`, etc.) inside macros. ([#9409](https://github.com/crystal-lang/crystal/pull/9409), thanks @asterite) ### Standard library - **(breaking-change)** Refactor to standardize on first argument for methods receiving `IO`. ([#9134](https://github.com/crystal-lang/crystal/pull/9134), [#9289](https://github.com/crystal-lang/crystal/pull/9289), [#9303](https://github.com/crystal-lang/crystal/pull/9303), [#9318](https://github.com/crystal-lang/crystal/pull/9318), thanks @straight-shoota, @bcardiff, @oprypin) - **(breaking-change)** Cleanup Digest and OpenSSL::Digest. ([#8426](https://github.com/crystal-lang/crystal/pull/8426), thanks @didactic-drunk) - Fix `Enum#to_s` for private enum. ([#9126](https://github.com/crystal-lang/crystal/pull/9126), thanks @straight-shoota) - Refactor `Benchmark::IPS::Entry` to use `UInt64` in `bytes_per_op`. ([#9081](https://github.com/crystal-lang/crystal/pull/9081), thanks @jhass) - Add `Experimental` annotation and doc label. ([#9244](https://github.com/crystal-lang/crystal/pull/9244), thanks @bcardiff) - Add subcommands to `OptionParser`. ([#9009](https://github.com/crystal-lang/crystal/pull/9009), [#9133](https://github.com/crystal-lang/crystal/pull/9133), thanks @RX14, @Sija) - Make `NamedTuple#sorted_keys` public. ([#9263](https://github.com/crystal-lang/crystal/pull/9263), thanks @waj) - Fix example codes in multiple places. ([#9203](https://github.com/crystal-lang/crystal/pull/9203), thanks @maiha) #### Macros - **(breaking-change)** Remove top-level `assert_responds_to` macro. ([#9085](https://github.com/crystal-lang/crystal/pull/9085), thanks @bcardiff) - **(breaking-change)** Drop top-level `parallel` macro. ([#9097](https://github.com/crystal-lang/crystal/pull/9097), thanks @bcardiff) - Fix lazy property not forwarding annotations. ([#9140](https://github.com/crystal-lang/crystal/pull/9140), thanks @asterite) - Add `host_flag?` macro method, not affected by cross-compilation. ([#9049](https://github.com/crystal-lang/crystal/pull/9049), thanks @oprypin) - Add `.each` and `.each_with_index` to various macro types. ([#9120](https://github.com/crystal-lang/crystal/pull/9120), thanks @Blacksmoke16) - Add `StringLiteral#titleize` macro method. ([#9269](https://github.com/crystal-lang/crystal/pull/9269), thanks @MakeNowJust) - Add `TypeNode` methods to check what "type" the node is. ([#9270](https://github.com/crystal-lang/crystal/pull/9270), thanks @Blacksmoke16) - Fix support `TypeNode.name(generic_args: false)` for generic instances. ([#9224](https://github.com/crystal-lang/crystal/pull/9224), thanks @Blacksmoke16) #### Numeric - **(breaking-change)** Add `Int#digits`, reverse `BigInt#digits` result. ([#9383](https://github.com/crystal-lang/crystal/pull/9383), thanks @asterite) - Fix overflow checking for operations with mixed sign. ([#9403](https://github.com/crystal-lang/crystal/pull/9403), thanks @waj) - Add `BigInt#factorial` using GMP. ([#9132](https://github.com/crystal-lang/crystal/pull/9132), thanks @peheje) #### Text - Add `String#titleize`. ([#9204](https://github.com/crystal-lang/crystal/pull/9204), thanks @hugopl) - Add `Regex#matches?` and `String#matches?`. ([#8989](https://github.com/crystal-lang/crystal/pull/8989), thanks @MakeNowJust) - Add `IO` overloads to various `String` case methods. ([#9236](https://github.com/crystal-lang/crystal/pull/9236), thanks @Blacksmoke16) - Improve docs examples regarding `Regex::MatchData`. ([#9010](https://github.com/crystal-lang/crystal/pull/9010), thanks @MakeNowJust) - Improve docs on `String` methods. ([#8447](https://github.com/crystal-lang/crystal/pull/8447), thanks @jan-zajic) #### Collections - **(breaking-change)** Add `Enumerable#first` with fallback block. ([#8999](https://github.com/crystal-lang/crystal/pull/8999), thanks @MakeNowJust) - Fix `Array#delete_at` bug with negative start index. ([#9399](https://github.com/crystal-lang/crystal/pull/9399), thanks @asterite) - Fix `Enumerable#{zip,zip?}` when self is an `Iterator`. ([#9330](https://github.com/crystal-lang/crystal/pull/9330), thanks @mneumann) - Make `Range#each` and `Range#reverse_each` work better with end/begin-less values. ([#9325](https://github.com/crystal-lang/crystal/pull/9325), thanks @asterite) - Improve docs on `Hash`. ([#8887](https://github.com/crystal-lang/crystal/pull/8887), thanks @rdp) #### Serialization - **(breaking-change)** Deprecate `JSON.mapping` and `YAML.mapping`. ([#9272](https://github.com/crystal-lang/crystal/pull/9272), thanks @straight-shoota) - **(breaking-change)** Make `INI` a module. ([#9408](https://github.com/crystal-lang/crystal/pull/9408), thanks @j8r) - Fix integration between `record` macro and `JSON::Serializable`/`YAML::Serializable` regarding default values. ([#9063](https://github.com/crystal-lang/crystal/pull/9063), thanks @Blacksmoke16) - Fix `XML.parse` invalid mem access in multi-thread. ([#9098](https://github.com/crystal-lang/crystal/pull/9098), thanks @bcardiff, @asterite) - Fix double string escape in `XML::Node#content=`. ([#9300](https://github.com/crystal-lang/crystal/pull/9300), thanks @straight-shoota) - Improve xpath regarding namespaces. ([#9288](https://github.com/crystal-lang/crystal/pull/9288), thanks @asterite) - Escape CDATA end sequences. ([#9230](https://github.com/crystal-lang/crystal/pull/9230), thanks @Blacksmoke16) - Add `JSON` and `YAML` serialization to `Path`. ([#9156](https://github.com/crystal-lang/crystal/pull/9156), thanks @straight-shoota) - Specify pkg-config name for `libyaml`. ([#9426](https://github.com/crystal-lang/crystal/pull/9426), thanks @jhass) - Specify pkg-config name for `libxml2`. ([#9436](https://github.com/crystal-lang/crystal/pull/9436), thanks @Blacksmoke16) - Make YAML specs robust against libyaml 0.2.5. ([#9427](https://github.com/crystal-lang/crystal/pull/9427), thanks @jhass) #### Time - **(breaking-change)** Support different number of fraction digits for RFC3339 time format. ([#9283](https://github.com/crystal-lang/crystal/pull/9283), thanks @waj) - Fix parsing AM/PM hours. ([#9334](https://github.com/crystal-lang/crystal/pull/9334), thanks @straight-shoota) - Improve `File.utime` precision from second to 100-nanosecond on Windows. ([#9344](https://github.com/crystal-lang/crystal/pull/9344), thanks @kubo) #### Files - **(breaking-change)** Move `Flate`, `Gzip`, `Zip`, `Zlib` to `Compress`. ([#8886](https://github.com/crystal-lang/crystal/pull/8886), thanks @bcardiff) - **(breaking-change)** Cleanup `File` & `FileUtils`. ([#9175](https://github.com/crystal-lang/crystal/pull/9175), thanks @bcardiff) - Fix realpath on macOS 10.15 (Catalina). ([#9296](https://github.com/crystal-lang/crystal/pull/9296), thanks @waj) - Fix `File#pos`, `File#seek` and `File#truncate` over 2G on Windows. ([#9015](https://github.com/crystal-lang/crystal/pull/9015), thanks @kubo) - Fix `File.rename` to overwrite the destination file on Windows, like elsewhere. ([#9038](https://github.com/crystal-lang/crystal/pull/9038), thanks @oprypin) - Fix `File`'s specs and related exception types on Windows. ([#9037](https://github.com/crystal-lang/crystal/pull/9037), thanks @oprypin) - Add support for `Path` arguments to multiple methods. ([#9153](https://github.com/crystal-lang/crystal/pull/9153), thanks @straight-shoota) - Add `Path#each_part` iterator. ([#9138](https://github.com/crystal-lang/crystal/pull/9138), thanks @straight-shoota) - Add `Path#relative_to`. ([#9169](https://github.com/crystal-lang/crystal/pull/9169), thanks @straight-shoota) - Add support for `Path` pattern to `Dir.glob`. ([#9420](https://github.com/crystal-lang/crystal/pull/9420), thanks @straight-shoota) - Implement `File#fsync` on Windows. ([#9257](https://github.com/crystal-lang/crystal/pull/9257), thanks @kubo) - Refactor `Path` regarding empty and `.`. ([#9137](https://github.com/crystal-lang/crystal/pull/9137), thanks @straight-shoota) #### Networking - **(breaking-change)** Make `IO#skip`, `IO#write` returns the number of bytes it skipped/written as `Int64`. ([#9233](https://github.com/crystal-lang/crystal/pull/9233), [#9363](https://github.com/crystal-lang/crystal/pull/9363), thanks @bcardiff) - **(breaking-change)** Improve error handling and logging in `HTTP::Server`. ([#9115](https://github.com/crystal-lang/crystal/pull/9115), [#9034](https://github.com/crystal-lang/crystal/pull/9034), thanks @waj, @straight-shoota) - **(breaking-change)** Change `HTTP::Request#remote_address` type to `Socket::Address?`. ([#9210](https://github.com/crystal-lang/crystal/pull/9210), thanks @waj) - Fix `flush` methods to always flush underlying `IO`. ([#9320](https://github.com/crystal-lang/crystal/pull/9320), thanks @straight-shoota) - Fix `HTTP::Server` sporadic failure in SSL handshake. ([#9177](https://github.com/crystal-lang/crystal/pull/9177), thanks @waj) - `WebSocket` shouldn't reply with same close code. ([#9313](https://github.com/crystal-lang/crystal/pull/9313), thanks @waj) - Ignore response body during `WebSocket` handshake. ([#9418](https://github.com/crystal-lang/crystal/pull/9418), thanks @waj) - Treat cookies which expire in this instant as expired. ([#9061](https://github.com/crystal-lang/crystal/pull/9061), thanks @RX14) - Set `sync` or `flush_on_newline` for standard I/O on Windows. ([#9207](https://github.com/crystal-lang/crystal/pull/9207), thanks @kubo) - Prefer HTTP basic authentication in OAuth2 client. ([#9127](https://github.com/crystal-lang/crystal/pull/9127), thanks @crush-157) - Defer request upgrade in `HTTP::Server` (aka: WebSockets). ([#9243](https://github.com/crystal-lang/crystal/pull/9243), thanks @waj) - Improve `URI::Punycode`, `HTTP::WebSocketHandler`, `HTTP::Status` documentation. ([#9068](https://github.com/crystal-lang/crystal/pull/9068), [#9130](https://github.com/crystal-lang/crystal/pull/9130), [#9180](https://github.com/crystal-lang/crystal/pull/9180), thanks @Blacksmoke16, @dscottboggs, @wontruefree) - Remove `HTTP::Params::Builder#to_s`, use underlying `IO` directly. ([#9319](https://github.com/crystal-lang/crystal/pull/9319), thanks @straight-shoota) - Fixed some regular failing specs in multi-thread mode. ([#9412](https://github.com/crystal-lang/crystal/pull/9412), thanks @bcardiff) #### Crypto - **(security)** Update SSL server secure defaults. ([#9026](https://github.com/crystal-lang/crystal/pull/9026), thanks @straight-shoota) - Add LibSSL `NO_TLS_V1_3` option. ([#9350](https://github.com/crystal-lang/crystal/pull/9350), thanks @lun-4) #### Logging - **(breaking-change)** Rename `Log::Severity::Warning` to `Warn`. Drop `Verbose`. Add `Trace` and `Notice`. ([#9293](https://github.com/crystal-lang/crystal/pull/9293), [#9107](https://github.com/crystal-lang/crystal/pull/9107), [#9316](https://github.com/crystal-lang/crystal/pull/9316), thanks @bcardiff, @paulcsmith) - **(breaking-change)** Allow local data on entries via `Log::Metadata` and redesign `Log::Context`. ([#9118](https://github.com/crystal-lang/crystal/pull/9118), [#9227](https://github.com/crystal-lang/crystal/pull/9227), [#9150](https://github.com/crystal-lang/crystal/pull/9150), [#9157](https://github.com/crystal-lang/crystal/pull/9157), thanks @bcardiff, @waj) - **(breaking-change)** Split top-level `Log::Metadata` from `Log::Metadata::Value`, drop immutability via clone, improve performance. ([#9295](https://github.com/crystal-lang/crystal/pull/9295), thanks @bcardiff) - **(breaking-change)** Rework `Log.setup_from_env` and defaults. ([#9145](https://github.com/crystal-lang/crystal/pull/9145), [#9240](https://github.com/crystal-lang/crystal/pull/9240), thanks @bcardiff) - Add `Log.capture` spec helper. ([#9201](https://github.com/crystal-lang/crystal/pull/9201), thanks @bcardiff) - Redesign `Log::Formatter`. ([#9211](https://github.com/crystal-lang/crystal/pull/9211), thanks @waj) - Add `to_json` for `Log::Context`. ([#9101](https://github.com/crystal-lang/crystal/pull/9101), thanks @paulcsmith) - Add `Log::IOBackend#new` with `formatter` named argument. ([#9105](https://github.com/crystal-lang/crystal/pull/9105), [#9434](https://github.com/crystal-lang/crystal/pull/9434), thanks @paulcsmith, @bcardiff) - Allow `nil` as context raw values. ([#9121](https://github.com/crystal-lang/crystal/pull/9121), thanks @bcardiff) - Add missing `Log#with_context`. ([#9058](https://github.com/crystal-lang/crystal/pull/9058), thanks @bcardiff) - Fix types referred in documentation. ([#9117](https://github.com/crystal-lang/crystal/pull/9117), thanks @bcardiff) - Allow override context within logging calls. ([#9146](https://github.com/crystal-lang/crystal/pull/9146), thanks @bcardiff) - Check severity before backend. ([#9400](https://github.com/crystal-lang/crystal/pull/9400), thanks @asterite) #### Concurrency - **(breaking-change)** Drop `Concurrent::Future` and top-level methods `delay`, `future`, `lazy`. Use [crystal-community/future.cr](https://github.com/crystal-community/future.cr). ([#9093](https://github.com/crystal-lang/crystal/pull/9093), thanks @bcardiff) #### System - **(breaking-change)** Deprecate `Process#kill`, use `Process#signal`. ([#9006](https://github.com/crystal-lang/crystal/pull/9006), thanks @oprypin, @jan-zajic) - `Process` raises `IO::Error` (or subclasses). ([#9340](https://github.com/crystal-lang/crystal/pull/9340), thanks @waj) - Add `Process.quote` and fix shell usages in the compiler. ([#9043](https://github.com/crystal-lang/crystal/pull/9043), [#9369](https://github.com/crystal-lang/crystal/pull/9369), thanks @oprypin, @bcardiff) - Implement `Process` support on Windows. ([#9047](https://github.com/crystal-lang/crystal/pull/9047), [#9021](https://github.com/crystal-lang/crystal/pull/9021), [#9122](https://github.com/crystal-lang/crystal/pull/9122), [#9112](https://github.com/crystal-lang/crystal/pull/9112), [#9149](https://github.com/crystal-lang/crystal/pull/9149), [#9310](https://github.com/crystal-lang/crystal/pull/9310), thanks @oprypin, @RX14, @kubo, @jan-zajic) - Fix compile-time checking of `dup3`/`clock_gettime` methods definition. ([#9407](https://github.com/crystal-lang/crystal/pull/9407), thanks @asterite) - Use `Int64` as portable `Process.pid` type. ([#9019](https://github.com/crystal-lang/crystal/pull/9019), thanks @oprypin) #### Runtime - **(breaking-change)** Deprecate top-level `fork`. ([#9136](https://github.com/crystal-lang/crystal/pull/9136), thanks @bcardiff) - **(breaking-change)** Move `Debug` to `Crystal` namespace. ([#9176](https://github.com/crystal-lang/crystal/pull/9176), thanks @bcardiff) - Fix segfaults when static linking with musl. ([#9238](https://github.com/crystal-lang/crystal/pull/9238), thanks @waj) - Allow calling `at_exit` inside `at_exit`. ([#9388](https://github.com/crystal-lang/crystal/pull/9388), thanks @asterite) - Rework DWARF loading and fix empty backtraces in musl. ([#9267](https://github.com/crystal-lang/crystal/pull/9267), thanks @waj) - Add DragonFly(BSD) support. ([#9178](https://github.com/crystal-lang/crystal/pull/9178), thanks @mneumann) - Add `Crystal::System::Process` to split out system-specific implementations. ([#9035](https://github.com/crystal-lang/crystal/pull/9035), thanks @oprypin) - Move internal `CallStack` to `Exception::CallStack`. ([#9076](https://github.com/crystal-lang/crystal/pull/9076), thanks @bcardiff) - Specify pkg-config name for `libevent`. ([#9395](https://github.com/crystal-lang/crystal/pull/9395), thanks @jhass) #### Spec - Reference global Spec in `be_a` macro. ([#9066](https://github.com/crystal-lang/crystal/pull/9066), thanks @asterite) - Add `-h` short flag to spec runner. ([#9164](https://github.com/crystal-lang/crystal/pull/9164), thanks @straight-shoota) - Fix `crystal spec` file paths on Windows. ([#9234](https://github.com/crystal-lang/crystal/pull/9234), thanks @oprypin) - Refactor spec hooks. ([#9090](https://github.com/crystal-lang/crystal/pull/9090), thanks @straight-shoota) ### Compiler - **(breaking-change)** Improve compiler single-file run syntax to make it shebang-friendly `#!`. ([#9171](https://github.com/crystal-lang/crystal/pull/9171), thanks @RX14) - **(breaking-change)** Use `Process.quote` for `crystal env` output. ([#9428](https://github.com/crystal-lang/crystal/pull/9428), thanks @MakeNowJust) - **(breaking-change)** Simplify `Link` annotation handling. ([#8972](https://github.com/crystal-lang/crystal/pull/8972), thanks @RX14) - Fix parsing of `foo:"bar"` inside call or named tuple. ([#9033](https://github.com/crystal-lang/crystal/pull/9033), thanks @asterite) - Fix parsing of anonymous splat and block arg. ([#9113](https://github.com/crystal-lang/crystal/pull/9113), thanks @MakeNowJust) - Fix parsing of `unless` inside macro. ([#9024](https://github.com/crystal-lang/crystal/pull/9024), [#9167](https://github.com/crystal-lang/crystal/pull/9167), thanks @MakeNowJust) - Fix parsing of `\` (backslash + space) inside regex literal to ` ` (space). ([#9079](https://github.com/crystal-lang/crystal/pull/9079), thanks @MakeNowJust) - Fix parsing of ambiguous '+' and '-'. ([#9194](https://github.com/crystal-lang/crystal/pull/9194), thanks @max-codeware) - Fix parsing of capitalized named argument. ([#9232](https://github.com/crystal-lang/crystal/pull/9232), thanks @asterite) - Fix parsing of `{[] of Foo, self.foo}` expressions. ([#9329](https://github.com/crystal-lang/crystal/pull/9329), thanks @MakeNowJust) - Fix cast fun function pointer to Proc. ([#9287](https://github.com/crystal-lang/crystal/pull/9287), thanks @asterite) - Make compiler warn on deprecated macros. ([#9343](https://github.com/crystal-lang/crystal/pull/9343), thanks @bcardiff) - Basic support for Win64 C lib ABI. ([#9387](https://github.com/crystal-lang/crystal/pull/9387), thanks @oprypin) - Make the compiler able to run on Windows and compile itself. ([#9054](https://github.com/crystal-lang/crystal/pull/9054), [#9062](https://github.com/crystal-lang/crystal/pull/9062), [#9095](https://github.com/crystal-lang/crystal/pull/9095), [#9106](https://github.com/crystal-lang/crystal/pull/9106), [#9307](https://github.com/crystal-lang/crystal/pull/9307), thanks @oprypin, @Sija) - Add docs regarding `CRYSTAL_OPTS`. ([#9018](https://github.com/crystal-lang/crystal/pull/9018), thanks @straight-shoota) - Remove `Process.run("which")` from compiler. ([#9141](https://github.com/crystal-lang/crystal/pull/9141), thanks @straight-shoota) - Refactor type parser. ([#9208](https://github.com/crystal-lang/crystal/pull/9208), thanks @MakeNowJust) - Refactor & clean-up in compiler. ([#8781](https://github.com/crystal-lang/crystal/pull/8781), [#9195](https://github.com/crystal-lang/crystal/pull/9195), thanks @rhysd, @straight-shoota) - Refactor `CrystalPath::Error`. ([#9359](https://github.com/crystal-lang/crystal/pull/9359), thanks @straight-shoota) - Refactor and improvements on spec_helper. ([#9367](https://github.com/crystal-lang/crystal/pull/9367), [#9059](https://github.com/crystal-lang/crystal/pull/9059), [#9393](https://github.com/crystal-lang/crystal/pull/9393), [#9351](https://github.com/crystal-lang/crystal/pull/9351), [#9402](https://github.com/crystal-lang/crystal/pull/9402), thanks @straight-shoota, @jhass, @oprypin) - Split general ABI specs from x86_64-specific ones, run on every platform. ([#9384](https://github.com/crystal-lang/crystal/pull/9384), thanks @oprypin) #### Language semantics - Fix `RegexLiteral#to_s` output when first character of literal is whitespace. ([#9017](https://github.com/crystal-lang/crystal/pull/9017), thanks @MakeNowJust) - Fix autocasting in multidispatch. ([#9004](https://github.com/crystal-lang/crystal/pull/9004), thanks @asterite) - Fix propagation of annotations into other scopes. ([#9125](https://github.com/crystal-lang/crystal/pull/9125), thanks @asterite) - Fix yield computation inside macro code. ([#9324](https://github.com/crystal-lang/crystal/pull/9324), thanks @asterite) - Fix incorrect type generated with `as?` when type is a union. ([#9417](https://github.com/crystal-lang/crystal/pull/9417), [#9435](https://github.com/crystal-lang/crystal/pull/9435), thanks @asterite) - Don't duplicate instance var in inherited generic type. ([#9433](https://github.com/crystal-lang/crystal/pull/9433), thanks @asterite) - Ensure `type_vars` works for generic modules. ([#9161](https://github.com/crystal-lang/crystal/pull/9161), thanks @toddsundsted) - Make autocasting work in default values against unions. ([#9366](https://github.com/crystal-lang/crystal/pull/9366), thanks @asterite) - Skip no closure check for non-Crystal procs. ([#9248](https://github.com/crystal-lang/crystal/pull/9248), thanks @jhass) #### Debugger - Improve debugging support. ([#8538](https://github.com/crystal-lang/crystal/pull/8538), thanks @skuznetsov) - Move recent additions to `DIBuilder` to `LLVMExt`. ([#9114](https://github.com/crystal-lang/crystal/pull/9114), thanks @bcardiff) ### Tools #### Formatter - Fix formatting of regex after some comments. ([#9109](https://github.com/crystal-lang/crystal/pull/9109), thanks @MakeNowJust) - Fix formatting of `&.!`. ([#9391](https://github.com/crystal-lang/crystal/pull/9391), thanks @MakeNowJust) - Avoid crash on heredoc with interpolations. ([#9382](https://github.com/crystal-lang/crystal/pull/9382), thanks @MakeNowJust) - Refactor: code clean-up. ([#9231](https://github.com/crystal-lang/crystal/pull/9231), thanks @MakeNowJust) #### Doc generator - Fix links to methods with `String` default values. ([#9200](https://github.com/crystal-lang/crystal/pull/9200), thanks @bcardiff) - Fix syntax highlighting of heredoc. ([#9396](https://github.com/crystal-lang/crystal/pull/9396), thanks @MakeNowJust) - Correctly attach docs before annotations to following types. ([#9332](https://github.com/crystal-lang/crystal/pull/9332), thanks @asterite) - Allow annotations and `:ditto:` in macro. ([#9341](https://github.com/crystal-lang/crystal/pull/9341), thanks @bcardiff) - Add project name and version to API docs. ([#8792](https://github.com/crystal-lang/crystal/pull/8792), thanks @straight-shoota) - Add version selector to API docs. ([#9074](https://github.com/crystal-lang/crystal/pull/9074), [#9187](https://github.com/crystal-lang/crystal/pull/9187), [#9250](https://github.com/crystal-lang/crystal/pull/9250), [#9252](https://github.com/crystal-lang/crystal/pull/9252), [#9254](https://github.com/crystal-lang/crystal/pull/9254), thanks @straight-shoota, @bcardiff) - Show input type path instead of full qualified path on generic. ([#9302](https://github.com/crystal-lang/crystal/pull/9302), thanks @MakeNowJust) - Remove README link in API docs. ([#9082](https://github.com/crystal-lang/crystal/pull/9082), thanks @straight-shoota) - Remove special handling for version tags in docs generator. ([#9083](https://github.com/crystal-lang/crystal/pull/9083), thanks @straight-shoota) - Refactor `is_crystal_repo` based on project name. ([#9070](https://github.com/crystal-lang/crystal/pull/9070), thanks @straight-shoota) - Refactor `Docs::Generator` source link generation. ([#9119](https://github.com/crystal-lang/crystal/pull/9119), [#9305](https://github.com/crystal-lang/crystal/pull/9305), thanks @straight-shoota) #### Playground - Allow building compiler without 'playground', to avoid dependency on sockets. ([#9031](https://github.com/crystal-lang/crystal/pull/9031), thanks @oprypin) - Add support to jquery version 3. ([#9028](https://github.com/crystal-lang/crystal/pull/9028), thanks @deiv) ### Others - CI improvements and housekeeping. ([#9012](https://github.com/crystal-lang/crystal/pull/9012), [#9129](https://github.com/crystal-lang/crystal/pull/9129), [#9242](https://github.com/crystal-lang/crystal/pull/9242), [#9370](https://github.com/crystal-lang/crystal/pull/9370), thanks @bcardiff) - Update to Shards 0.11.1. ([#9446](https://github.com/crystal-lang/crystal/pull/9446), thanks @bcardiff) - Tidy up Makefile and crystal env output. ([#9423](https://github.com/crystal-lang/crystal/pull/9423), thanks @bcardiff) - Always include `lib` directory in the `CRYSTAL_PATH`. ([#9315](https://github.com/crystal-lang/crystal/pull/9315), thanks @waj) - Use `SOURCE_DATE_EPOCH` only to determine compiler date. ([#9088](https://github.com/crystal-lang/crystal/pull/9088), thanks @straight-shoota) - Win CI: Bootstrap Crystal, build things on Windows, publish the binary. ([#9123](https://github.com/crystal-lang/crystal/pull/9123), [#9155](https://github.com/crystal-lang/crystal/pull/9155), [#9144](https://github.com/crystal-lang/crystal/pull/9144), [#9346](https://github.com/crystal-lang/crystal/pull/9346), thanks @oprypin) - Regenerate implementation tool sample. ([#9003](https://github.com/crystal-lang/crystal/pull/9003), thanks @nulty) - Avoid requiring non std-lib spec spec_helper. ([#9294](https://github.com/crystal-lang/crystal/pull/9294), thanks @bcardiff) - Improve grammar and fix typos. ([#9087](https://github.com/crystal-lang/crystal/pull/9087), [#9212](https://github.com/crystal-lang/crystal/pull/9212), [#9368](https://github.com/crystal-lang/crystal/pull/9368), thanks @MakeNowJust, @j8r) - Hide internal functions in docs. ([#9410](https://github.com/crystal-lang/crystal/pull/9410), thanks @bcardiff) - Advertise full `crystal spec` command for running a particular spec. ([#9103](https://github.com/crystal-lang/crystal/pull/9103), thanks @paulcsmith) - Update README. ([#9225](https://github.com/crystal-lang/crystal/pull/9225), [#9163](https://github.com/crystal-lang/crystal/pull/9163), thanks @danimiba, @straight-shoota) - Fix LICENSE and add NOTICE file. ([#3903](https://github.com/crystal-lang/crystal/pull/3903), thanks @MakeNowJust) ## 0.34.0 (2020-04-06) ### Language changes - **(breaking-change)** Exhaustive `case` expression check added, for now it produces warnings. ([#8424](https://github.com/crystal-lang/crystal/pull/8424), [#8962](https://github.com/crystal-lang/crystal/pull/8962), thanks @asterite, @Sija) - Let `Proc(T)` be used as a `Proc(Nil)`. ([#8969](https://github.com/crystal-lang/crystal/pull/8969), [#8970](https://github.com/crystal-lang/crystal/pull/8970), thanks @asterite) ### Standard library - **(breaking-change)** Replace `Errno`, `WinError`, `IO::Timeout` with `RuntimeError`, `IO::TimeoutError`, `IO::Error`, `File::Error`, `Socket::Error`, and subclasses. ([#8885](https://github.com/crystal-lang/crystal/pull/8885), thanks @waj) - **(breaking-change)** Replace `Logger` module in favor of `Log` module. ([#8847](https://github.com/crystal-lang/crystal/pull/8847), [#8976](https://github.com/crystal-lang/crystal/pull/8976), thanks @bcardiff) - **(breaking-change)** Move `Adler32` and `CRC32` to `Digest`. ([#8881](https://github.com/crystal-lang/crystal/pull/8881), thanks @bcardiff) - **(breaking-change)** Remove `DL` module. ([#8882](https://github.com/crystal-lang/crystal/pull/8882), thanks @bcardiff) - Enable more win32 specs. ([#8683](https://github.com/crystal-lang/crystal/pull/8683), [#8822](https://github.com/crystal-lang/crystal/pull/8822), thanks @straight-shoota) - Make `SemanticVersion::Prerelease` comparable. ([#8991](https://github.com/crystal-lang/crystal/pull/8991), thanks @MakeNowJust) - Use `flag?(:i386)` instead of obsolete `flag?(:i686)`. ([#8863](https://github.com/crystal-lang/crystal/pull/8863), thanks @bcardiff) - Remove Windows workaround using `vsnprintf`. ([#8942](https://github.com/crystal-lang/crystal/pull/8942), thanks @oprypin) - Fixed docs broken link to ruby's prettyprint source. ([#8915](https://github.com/crystal-lang/crystal/pull/8915), thanks @matthin) - Update `OptionParser` example to exit on `--help`. ([#8927](https://github.com/crystal-lang/crystal/pull/8927), thanks @vlazar) #### Numeric - Fixed `Float32#to_s` corner-case. ([#8838](https://github.com/crystal-lang/crystal/pull/8838), thanks @toddsundsted) - Fixed make `Big*#to_u` raise on negative values. ([#8826](https://github.com/crystal-lang/crystal/pull/8826), thanks @Sija) - Fixed `BigDecimal#to_big_i` regression. ([#8790](https://github.com/crystal-lang/crystal/pull/8790), thanks @Sija) - Add `Complex#round`. ([#8819](https://github.com/crystal-lang/crystal/pull/8819), thanks @miketheman) - Add `Int#bit_length` and `BigInt#bit_length`. ([#8924](https://github.com/crystal-lang/crystal/pull/8924), [#8931](https://github.com/crystal-lang/crystal/pull/,8931), thanks @asterite) - Fixed docs of `Int#gcd`. ([#8894](https://github.com/crystal-lang/crystal/pull/8894), thanks @nard-tech) #### Text - **(breaking-change)** Deprecate top-level `with_color` in favor of `Colorize.with`. ([#8892](https://github.com/crystal-lang/crystal/pull/8892), [#8958](https://github.com/crystal-lang/crystal/pull/8958), thanks @bcardiff, @oprypin) - Add overloads for `String#ljust`, `String#rjust` and `String#center` that take an `IO`. ([#8923](https://github.com/crystal-lang/crystal/pull/8923), thanks @asterite) - Add missing `Regex#hash` and `Regex::MatchData#hash`. ([#8986](https://github.com/crystal-lang/crystal/pull/8986), thanks @MakeNowJust) - Upgrade Unicode to 13.0.0. ([#8906](https://github.com/crystal-lang/crystal/pull/8906), thanks @Blacksmoke16) - Revert deprecation of `String#codepoint_at`. ([#8902](https://github.com/crystal-lang/crystal/pull/8902), thanks @vlazar) - Move `Iconv` to `Crystal` namespace. ([#8890](https://github.com/crystal-lang/crystal/pull/8890), thanks @bcardiff) #### Collections - Fixed make `Range#size` raise on an open range. ([#8829](https://github.com/crystal-lang/crystal/pull/8829), thanks @Sija) - Add `Enumerable#empty?`. ([#8960](https://github.com/crystal-lang/crystal/pull/8960), thanks @Sija) - **(performance)** Optimized Implementation of `Array#fill` for zero Values. ([#8903](https://github.com/crystal-lang/crystal/pull/8903), thanks @toddsundsted) - Refactor `Reflect` to an `Enumerable` private definition. ([#8884](https://github.com/crystal-lang/crystal/pull/8884), thanks @bcardiff) #### Serialization - **(breaking-change)** Rename `YAML::Builder.new` with block to `YAML::Builder.build`. ([#8896](https://github.com/crystal-lang/crystal/pull/8896), thanks @straight-shoota) - Add `XML.build_fragment`. ([#8813](https://github.com/crystal-lang/crystal/pull/8813), thanks @straight-shoota) - Add `CSV#rewind`. ([#8912](https://github.com/crystal-lang/crystal/pull/8912), thanks @asterite) - Add `Deque#from_json` and `Deque#to_json`. ([#8850](https://github.com/crystal-lang/crystal/pull/8850), thanks @carlhoerberg) - Call to `IO#flush` on `CSV`, `INI`, `JSON`, `XML`, and `YAML` builders. ([#8876](https://github.com/crystal-lang/crystal/pull/8876), thanks @asterite) - Add docs to `Object.from_yaml`. ([#8800](https://github.com/crystal-lang/crystal/pull/8800), thanks @wowinter13) #### Time - **(breaking-change)** Improve `Time::Span` initialization API with mandatory named arguments. ([#8257](https://github.com/crystal-lang/crystal/pull/8257), [#8857](https://github.com/crystal-lang/crystal/pull/8857), thanks @dnamsons, @bcardiff) - Add `Time::Span#total_microseconds`. ([#8966](https://github.com/crystal-lang/crystal/pull/8966), thanks @vlazar) #### Files - Fixed multi-thread race condition by setting `fd` to `-1` on closed `File`/`Socket`. ([#8873](https://github.com/crystal-lang/crystal/pull/8873), thanks @bcardiff) - Fixed `File.dirname` with unicode chars. ([#8911](https://github.com/crystal-lang/crystal/pull/8911), thanks @asterite) - Add `IO::Buffered#flush_on_newline` back and set it to true for non-tty. ([#8935](https://github.com/crystal-lang/crystal/pull/8935), thanks @asterite) - Forward missing methods of `IO::Hexdump` to underlying `IO`. ([#8908](https://github.com/crystal-lang/crystal/pull/8908), thanks @carlhoerberg) #### Networking - **(breaking-change)** Correctly support WebSocket close codes. ([#8975](https://github.com/crystal-lang/crystal/pull/8975), [#8981](https://github.com/crystal-lang/crystal/pull/8981), thanks @RX14, @Sija) - Make `HTTP::Client` return empty `body_io` if content-length is zero. ([#8503](https://github.com/crystal-lang/crystal/pull/8503), thanks @asterite) - Fixed `UDP` specs in the case of a local firewall. ([#8817](https://github.com/crystal-lang/crystal/pull/8817), thanks @RX14) - Fixed `MIME` spec examples to not collide with actual registry. ([#8795](https://github.com/crystal-lang/crystal/pull/8795), thanks @straight-shoota) - Fixed `UNIXServer`, and `HTTP::WebSocket` specs to ensure server is accepting before closing. ([#8755](https://github.com/crystal-lang/crystal/pull/8755), [#8879](https://github.com/crystal-lang/crystal/pull/8879), thanks @bcardiff) - Add type annotation to `tls` argument in `HTTP`. ([#8678](https://github.com/crystal-lang/crystal/pull/8678), thanks @j8r) - Add `Location` to `HTTP::Request` common header names. ([#8992](https://github.com/crystal-lang/crystal/pull/8992), thanks @mamantoha) #### Concurrency - Add docs on `Future` regarding exceptions. ([#8860](https://github.com/crystal-lang/crystal/pull/8860), thanks @rdp) - Disable occasionally failing `Thread` specs on musl. ([#8801](https://github.com/crystal-lang/crystal/pull/8801), thanks @straight-shoota) #### System - Fixed typo on `src/signal.cr`. ([#8805](https://github.com/crystal-lang/crystal/pull/8805), thanks @lbguilherme) #### Runtime - Fixed exceptions not being inspectable when running binary from PATH. ([#8807](https://github.com/crystal-lang/crystal/pull/8807), thanks @willhbr) - Move `AtExitHandlers` to `Crystal` namespace. ([#8883](https://github.com/crystal-lang/crystal/pull/8883), thanks @bcardiff) ### Compiler - **(breaking-change)** Drop `disable_overflow` compiler flag. ([#8772](https://github.com/crystal-lang/crystal/pull/8772), thanks @Sija) - Fixed url in "can't infer block return type" error message. ([#8869](https://github.com/crystal-lang/crystal/pull/8869), thanks @nilium) - Fixed typo in math interpreter error message. ([#8941](https://github.com/crystal-lang/crystal/pull/8941), thanks @j8r) - Use `CRYSTAL_OPTS` environment variable as default compiler options. ([#8900](https://github.com/crystal-lang/crystal/pull/8900), thanks @bcardiff) - Avoid using the default `--exclude-warnings` value if some is specified. ([#8899](https://github.com/crystal-lang/crystal/pull/8899), thanks @bcardiff) - Honor `LIBRARY_PATH` as default library path, and allow linking with no explicit `/usr/lib:/usr/local/lib` paths. ([#8948](https://github.com/crystal-lang/crystal/pull/8948), thanks @bcardiff) - Fix Windows LLVM globals codegen in non-single-module mode. ([#8978](https://github.com/crystal-lang/crystal/pull/8978), thanks @oprypin) - Add support for LLVM 10. ([#8940](https://github.com/crystal-lang/crystal/pull/8940), thanks @RX14) - Remove redundant calls to `Object.to_s` in interpolation in compiler's code. ([#8947](https://github.com/crystal-lang/crystal/pull/8947), thanks @veelenga) #### Language semantics - Type as `NoReturn` if calling method on abstract class with no concrete subclasses. ([#8870](https://github.com/crystal-lang/crystal/pull/8870), thanks @asterite) ### Tools - Add `crystal init` name validation. ([#8737](https://github.com/crystal-lang/crystal/pull/8737), thanks @straight-shoota) #### Doc generator - Show warnings on docs command. ([#8880](https://github.com/crystal-lang/crystal/pull/8880), thanks @bcardiff) ### Others - CI improvements and housekeeping. ([#8804](https://github.com/crystal-lang/crystal/pull/8804), [#8811](https://github.com/crystal-lang/crystal/pull/8811), [#8982](https://github.com/crystal-lang/crystal/pull/8982), thanks @bcardiff, @oprypin) - Update to Shards 0.10.0. ([#8988](https://github.com/crystal-lang/crystal/pull/8988), thanks @bcardiff) - Fix `pretty_json` sample. ([#8816](https://github.com/crystal-lang/crystal/pull/8816), thanks @asterite) - Fix typos throughout the codebase. ([#8971](https://github.com/crystal-lang/crystal/pull/8971), thanks @Sija) ## 0.33.0 (2020-02-14) ### Language changes - Allow `timeout` in select statements. ([#8506](https://github.com/crystal-lang/crystal/pull/8506), [#8705](https://github.com/crystal-lang/crystal/pull/8705), thanks @bcardiff, @firejox, @vlazar) #### Macros - Add `TypeNode#name(generic_args : BoolLiteral)` to return `TypeNode`'s name with or without type vars. ([#8483](https://github.com/crystal-lang/crystal/pull/8483), thanks @Blacksmoke16) ### Standard library - **(breaking-change)** Remove several previously deprecated methods and modules: `PartialComparable`, `Crypto::Bcrypt::Password#==`, `HTTP::Server::Response#respond_with_error`, `JSON::PullParser::Kind#==`, `Symbol#==(JSON::PullParser::Kind)`, `JSON::Token#type`, `String#at`, `Time.new`, `Time.now`, `Time.utc_now`, `URI.escape`, `URI.unescape`. ([#8646](https://github.com/crystal-lang/crystal/pull/8646), [#8596](https://github.com/crystal-lang/crystal/pull/8596), thanks @bcardiff, @Blacksmoke16) - Fixed docs wording. ([#8606](https://github.com/crystal-lang/crystal/pull/8606), [#8784](https://github.com/crystal-lang/crystal/pull/8784), thanks @fxn) - Add `Object#in?`. ([#8720](https://github.com/crystal-lang/crystal/pull/8720), [#8723](https://github.com/crystal-lang/crystal/pull/8723), thanks @Sija) - Allow to create an enum from a symbol. ([#8634](https://github.com/crystal-lang/crystal/pull/8634), thanks @bew) - Add `VaList#next` for getting the next element in a variadic argument list. ([#8535](https://github.com/crystal-lang/crystal/pull/8535), [#8688](https://github.com/crystal-lang/crystal/pull/8688), thanks @ffwff, @RX14) - Refactor `ARGF` implementation. ([#8593](https://github.com/crystal-lang/crystal/pull/8593), thanks @arcage) - Fixed specs of `Colorize` on dumb terminal. ([#8673](https://github.com/crystal-lang/crystal/pull/8673), thanks @oprypin) - Fixed some specs on Win32. ([#8670](https://github.com/crystal-lang/crystal/pull/8670), thanks @straight-shoota) #### Numeric - Add `BigInt#unsafe_shr`. ([#8763](https://github.com/crystal-lang/crystal/pull/8763), thanks @asterite) - Refactor `Float#fdiv` to use binary primitive. ([#8662](https://github.com/crystal-lang/crystal/pull/8662), thanks @bcardiff) #### Text - Fixed `\u0000` wrongly added on `String#sub(Hash)` replaces last char. ([#8644](https://github.com/crystal-lang/crystal/pull/8644), thanks @mimame) #### Collections - Fixed `Enumerable#zip` to work with union types. ([#8621](https://github.com/crystal-lang/crystal/pull/8621), thanks @asterite) - Fixed docs regarding `Hash`'s `initial_capacity`. ([#8569](https://github.com/crystal-lang/crystal/pull/8569), thanks @r00ster91) #### Serialization - Improved JSON deserialization into union types. ([#8689](https://github.com/crystal-lang/crystal/pull/8689), thanks @KimBurgess) - Fixed expected error message in libxml2 error spec. ([#8699](https://github.com/crystal-lang/crystal/pull/8699), thanks @straight-shoota) - Fixed `JSON::PullParser` overflow handling. ([#8698](https://github.com/crystal-lang/crystal/pull/8698), thanks @KimBurgess) - Fixed `JSON::Any#dig?`/`YAML::Any#dig?` on non-structure values. ([#8745](https://github.com/crystal-lang/crystal/pull/8745), thanks @Sija) #### Time - Fixed `Time#shift` over date boundaries with zone offset. ([#8742](https://github.com/crystal-lang/crystal/pull/8742), thanks @straight-shoota) #### Files - **(breaking-change)** Deprecate `File::Info#owner`, and `File::Info#group`; use `owner_id`, and `group_id`. ([#8007](https://github.com/crystal-lang/crystal/pull/8007), thanks @j8r) - Fixed `Path.new` receiving `Path` as first argument. ([#8753](https://github.com/crystal-lang/crystal/pull/8753), thanks @straight-shoota) - Fixed `File.size` and `File.info` to work with `Path` parameters. ([#8625](https://github.com/crystal-lang/crystal/pull/8625), thanks @snluu) - Fixed `Path` specs when `ENV["HOME"]` is unset. ([#8667](https://github.com/crystal-lang/crystal/pull/8667), thanks @straight-shoota) - Refactor `Dir.mkdir_p` to use `Path#each_parent` and make it work on Win32. ([#8668](https://github.com/crystal-lang/crystal/pull/8668), thanks @straight-shoota) - Fixed `IO::MultiWriter` specs to close file before reading/deleting it. ([#8674](https://github.com/crystal-lang/crystal/pull/8674), thanks @oprypin) #### Networking - Fixed invalid call to libevent and race conditions on closed `IO` when resuming readable/writable event. ([#8707](https://github.com/crystal-lang/crystal/pull/8707), [#8733](https://github.com/crystal-lang/crystal/pull/8733), thanks @bcardiff) - Fixed unexpected EOF in terminated SSL connection. ([#8540](https://github.com/crystal-lang/crystal/pull/8540), thanks @rdp) - Fixed `HTTP::Cookie` to support `Int64` max-age values. ([#8759](https://github.com/crystal-lang/crystal/pull/8759), thanks @asterite) - Improve error message for `getaddrinfo` failure. ([#8498](https://github.com/crystal-lang/crystal/pull/8498), thanks @rdp) - Make `IO::SysCall#wait_readable` and `IO::SysCall#wait_writable` public, yet `:nodoc:`. ([#7366](https://github.com/crystal-lang/crystal/pull/7366), thanks @stakach) - Refactor `StaticFileHandler` to use `Path`. ([#8672](https://github.com/crystal-lang/crystal/pull/8672), thanks @straight-shoota) - Remove fixed date in spec. ([#8640](https://github.com/crystal-lang/crystal/pull/8640), thanks @bcardiff) - Remove non-portable error message in `TCPServer` spec. ([#8702](https://github.com/crystal-lang/crystal/pull/8702), thanks @straight-shoota) #### Crypto - Add `Crypto::Bcrypt::Password` check for invalid hash value. ([#6467](https://github.com/crystal-lang/crystal/pull/6467), thanks @miketheman) - Improve documentation for `Random::Secure`. ([#8484](https://github.com/crystal-lang/crystal/pull/8484), thanks @straight-shoota) #### Concurrency - Fixed `Future(Nil)` when the block raises. ([#8650](https://github.com/crystal-lang/crystal/pull/8650), thanks @lbguilherme) - Fixed `IO` closing in multi-thread mode. ([#8733](https://github.com/crystal-lang/crystal/pull/8733), thanks @bcardiff) - Fixed some regular failing specs in multi-thread mode. ([#8592](https://github.com/crystal-lang/crystal/pull/8592), [#8643](https://github.com/crystal-lang/crystal/pull/8643), [#8724](https://github.com/crystal-lang/crystal/pull/8724), [#8761](https://github.com/crystal-lang/crystal/pull/8761), thanks @bcardiff) - Add docs to `Fiber`. ([#8739](https://github.com/crystal-lang/crystal/pull/8739), thanks @straight-shoota) #### System - Enable `system` module for Win32 in prelude. ([#8661](https://github.com/crystal-lang/crystal/pull/8661), thanks @straight-shoota) - Handle exceptions raised at `__crystal_sigfault_handler`. ([#8743](https://github.com/crystal-lang/crystal/pull/8743), thanks @waj) #### Runtime - Fixed wrongly collected exception object by the GC. Ensure `LibUnwind::Exception` struct is not atomic. ([#8728](https://github.com/crystal-lang/crystal/pull/8728), thanks @waj) - Fixed reporting of non-statement rows in DWARF backtrace. ([#8499](https://github.com/crystal-lang/crystal/pull/8499), thanks @rdp) - Add top level exception handler. ([#8735](https://github.com/crystal-lang/crystal/pull/8735), [#8791](https://github.com/crystal-lang/crystal/pull/8791), thanks @waj) - Try to open stdio in non-blocking mode. ([#8787](https://github.com/crystal-lang/crystal/pull/8787), thanks @waj) - Allow `Crystal::System.print_error` to use `printf` like format. ([#8786](https://github.com/crystal-lang/crystal/pull/8786), thanks @bcardiff) #### Spec - **(breaking-change)** Remove previously deprecated spec method `assert`. ([#8767](https://github.com/crystal-lang/crystal/pull/8767), thanks @Blacksmoke16) - `Spec::JUnitFormatter` output and options enhancements. ([#8599](https://github.com/crystal-lang/crystal/pull/8599), [#8692](https://github.com/crystal-lang/crystal/pull/8692), thanks @Sija, @bcardiff) ### Compiler - **(breaking-change)** Drop support for previously deprecated comma separators in enums and other cleanups. ([#8657](https://github.com/crystal-lang/crystal/pull/8657), thanks @bcardiff) - **(breaking-change)** Drop uppercase F32 and F64 float number suffixes. ([#8782](https://github.com/crystal-lang/crystal/pull/8782), thanks @rhysd) - Fixed memory corruption issues by using LLVM's `memset` and `memcpy` that matches target machine. ([#8746](https://github.com/crystal-lang/crystal/pull/8746), thanks @bcardiff) - Fixed ICE when trying to add type inside annotation. ([#8628](https://github.com/crystal-lang/crystal/pull/8628), thanks @asterite) - Fixed ICE on `typeof` in an unused block. ([#8695](https://github.com/crystal-lang/crystal/pull/8695), thanks @asterite) - Fixed ICE in case of wrong target triple. ([#8710](https://github.com/crystal-lang/crystal/pull/8710), thanks @Sija) - Fixed ICE when raising a macro exception with empty message. ([#8654](https://github.com/crystal-lang/crystal/pull/8654), thanks @jan-zajic) - Fixed parser bug macro with "eenum" in it. ([#8760](https://github.com/crystal-lang/crystal/pull/8760), thanks @asterite) - Change `CRYSTAL_PATH` to allow shards to override std-lib. ([#8752](https://github.com/crystal-lang/crystal/pull/8752), thanks @bcardiff) #### Language semantics - Fixed missing virtualization of `Proc` pointer. ([#8757](https://github.com/crystal-lang/crystal/pull/8757), thanks @asterite) - Fixed type of vars after `begin`/`rescue` if all `rescue` are unreachable. ([#8758](https://github.com/crystal-lang/crystal/pull/8758), thanks @asterite) - Fixed visibility propagation to macro expansions in all cases. ([#8762](https://github.com/crystal-lang/crystal/pull/8762), [#8796](https://github.com/crystal-lang/crystal/pull/8796), thanks @asterite) ### Tools - Update `crystal init` to handle `.`. ([#8681](https://github.com/crystal-lang/crystal/pull/8681), thanks @jethrodaniel) #### Formatter - Fixed indent after comment inside indexer. ([#8627](https://github.com/crystal-lang/crystal/pull/8627), thanks @asterite) - Fixed indent of comments at the end of a proc literal. ([#8778](https://github.com/crystal-lang/crystal/pull/8778), thanks @asterite) - Fixed crash when formatting comment after macro. ([#8697](https://github.com/crystal-lang/crystal/pull/8697), thanks @asterite) - Fixed crash when formatting `exp.!`. ([#8768](https://github.com/crystal-lang/crystal/pull/8768), thanks @asterite) - Removes unnecessary escape sequences. ([#8619](https://github.com/crystal-lang/crystal/pull/8619), thanks @RX14) #### Doc generator - **(breaking-change)** Deprecate `ditto` and `nodoc` in favor of `:ditto:` and `:nodoc:`. ([#6362](https://github.com/crystal-lang/crystal/pull/6362), thanks @j8r) - Skip creation of `docs/` dir when not needed. ([#8718](https://github.com/crystal-lang/crystal/pull/8718), thanks @Sija) ### Others - CI improvements and housekeeping. ([#8580](https://github.com/crystal-lang/crystal/pull/8580), [#8597](https://github.com/crystal-lang/crystal/pull/8597), [#8679](https://github.com/crystal-lang/crystal/pull/8679), [#8779](https://github.com/crystal-lang/crystal/pull/8779), thanks @bcardiff, @j8r) - Add Windows CI using GitHub Actions. ([#8676](https://github.com/crystal-lang/crystal/pull/8676), thanks @oprypin) - Add Alpine CI using CircleCI. ([#7420](https://github.com/crystal-lang/crystal/pull/7420), thanks @straight-shoota) - Build Alpine Docker images. ([#8708](https://github.com/crystal-lang/crystal/pull/8708), thanks @straight-shoota) - Allow `Makefile` to use `lld` if present (Linux only). ([#8641](https://github.com/crystal-lang/crystal/pull/8641), thanks @bcardiff) - Simplify script to determine installed LLVM version. ([#8605](https://github.com/crystal-lang/crystal/pull/8605), thanks @j8r) - Add CircleCI test summaries. ([#8617](https://github.com/crystal-lang/crystal/pull/8617), thanks @Sija) - Add helper scripts to identify working std-lib specs on Win32. ([#8664](https://github.com/crystal-lang/crystal/pull/8664), thanks @straight-shoota) ## 0.32.1 (2019-12-18) ### Standard library #### Collections - Fixed docs of `Enumerable#each_cons_pair` and `Iterator#cons_pair`. ([#8585](https://github.com/crystal-lang/crystal/pull/8585), thanks @arcage) #### Networking - Fixed `HTTP::WebSocket`'s `on_close` callback is called for all errors. ([#8552](https://github.com/crystal-lang/crystal/pull/8552), thanks @stakach) - Fixed sporadic failure in specs with OpenSSL 1.1+. ([#8582](https://github.com/crystal-lang/crystal/pull/8582), thanks @rdp) ### Compiler #### Language semantics - Combine contiguous string literals before string interpolation. ([#8581](https://github.com/crystal-lang/crystal/pull/8581), thanks @asterite) ## 0.32.0 (2019-12-11) ### Language changes - Allow boolean negation to be written also as a regular method call `expr.!`. ([#8445](https://github.com/crystal-lang/crystal/pull/8445), thanks @jan-zajic) #### Macros - Add `TypeNode#class_vars` to list class variables of a type in a macro. ([#8405](https://github.com/crystal-lang/crystal/pull/8405), thanks @jan-zajic) - Add `TypeNode#includers` to get an array of types a module is directly included in. ([#8133](https://github.com/crystal-lang/crystal/pull/8133), thanks @Blacksmoke16) - Add `ArrayLiteral#map_with_index` and `TupleLiteral#map_with_index`. ([#8049](https://github.com/crystal-lang/crystal/pull/8049), thanks @Blacksmoke16) - Add docs for `ArrayLiteral#reduce`. ([#8379](https://github.com/crystal-lang/crystal/pull/8379), thanks @jan-zajic) - Add `lower:` named argument to `StringLiteral#camelcase`. ([#8429](https://github.com/crystal-lang/crystal/pull/8429), thanks @Blacksmoke16) ### Standard library - **(breaking-change)** Remove `Readline` from std-lib. It's now available as a shard at [crystal-lang/crystal-readline](https://www.github.com/crystal-lang/crystal-readline) ([#8364](https://github.com/crystal-lang/crystal/pull/8364), thanks @ftarulla) - Move `Number#clamp` to `Comparable#clamp`. ([#8522](https://github.com/crystal-lang/crystal/pull/8522), thanks @wontruefree) - Allow `abort` without arguments. ([#8214](https://github.com/crystal-lang/crystal/pull/8214), thanks @dbackeus) - Improve error message for not-nil assertion in getters. ([#8200](https://github.com/crystal-lang/crystal/pull/8200), [#8296](https://github.com/crystal-lang/crystal/pull/8296), thanks @icy-arctic-fox) - Add `Enum.valid?`. ([#5716](https://github.com/crystal-lang/crystal/pull/5716), thanks @MakeNowJust) - Disable colored output if `TERM=dumb`. ([#8271](https://github.com/crystal-lang/crystal/pull/8271), thanks @ilanpillemer) - Documentation improvements. ([#7656](https://github.com/crystal-lang/crystal/pull/7656), [#8337](https://github.com/crystal-lang/crystal/pull/8337), [#8446](https://github.com/crystal-lang/crystal/pull/8446), thanks @r00ster91, @vlazar, @cserb) - Add docs for pseudo methods. ([#8327](https://github.com/crystal-lang/crystal/pull/8327), [#8491](https://github.com/crystal-lang/crystal/pull/8491), thanks @straight-shoota) - Code cleanups. ([#8270](https://github.com/crystal-lang/crystal/pull/8270), [#8368](https://github.com/crystal-lang/crystal/pull/8368), [#8404](https://github.com/crystal-lang/crystal/pull/8404), thanks @asterite, @vlazar, @arcage) #### Numeric - Fixed `%` and `Int#remainder` edge case of min int value against `-1`. ([#8321](https://github.com/crystal-lang/crystal/pull/8321), thanks @asterite) - Fixed `Int#gcd` types edge case and improve performance. ([#7996](https://github.com/crystal-lang/crystal/pull/7996), [#8419](https://github.com/crystal-lang/crystal/pull/8419), thanks @yxhuvud, @j8r) - Add `Int#bits` for accessing bit ranges. ([#8165](https://github.com/crystal-lang/crystal/pull/8165), thanks @stakach) - Allow `Number#round` with `UInt` argument. ([#8361](https://github.com/crystal-lang/crystal/pull/8361), thanks @igor-alexandrov) #### Text - **(breaking-change)** Implement string interpolation as a call to `String.interpolation`. ([#8400](https://github.com/crystal-lang/crystal/pull/8400), thanks @asterite) - **(breaking-change)** Deprecate `String#codepoint_at`, use `char_at(index).ord`. ([#8475](https://github.com/crystal-lang/crystal/pull/8475), thanks @vlazar) - Fixed encoding specs for musl iconv. ([#8525](https://github.com/crystal-lang/crystal/pull/8525), thanks @straight-shoota) - Add `String#presence`. ([#8345](https://github.com/crystal-lang/crystal/pull/8345), [#8508](https://github.com/crystal-lang/crystal/pull/8508), thanks @igor-alexandrov, @Sija) - Add `String#center`. ([#8557](https://github.com/crystal-lang/crystal/pull/8557), thanks @hutou) - **(performance)** Refactor `String#to_utf16` optimizing for ascii-only. ([#8526](https://github.com/crystal-lang/crystal/pull/8526), thanks @straight-shoota) - Add docs in `Levenshtein` module. ([#8386](https://github.com/crystal-lang/crystal/pull/8386), thanks @katafrakt) - Add docs to `Regex::Options`. ([#8448](https://github.com/crystal-lang/crystal/pull/8448), thanks @jan-zajic) #### Collections - **(breaking-change)** Deprecate `Enumerable#grep`, use `Enumerable#select`. ([#8452](https://github.com/crystal-lang/crystal/pull/8452), thanks @j8r) - Fixed `Enumerable#minmax`, `#min`, `#max` for partially comparable values. ([#8490](https://github.com/crystal-lang/crystal/pull/8490), thanks @TedTran2019) - Fixed `Hash#rehash`. ([#8450](https://github.com/crystal-lang/crystal/pull/8450), thanks @asterite) - Fixed `Array` range assignment index out of bounds. ([#8347](https://github.com/crystal-lang/crystal/pull/8347), thanks @asterite) - Fixed endless ranged support for `String#[]?` and `Array#[]?`. ([#8567](https://github.com/crystal-lang/crystal/pull/8567), thanks @KarthikMAM) - Add `Hash#compare_by_identity` and `Set#compare_by_identity`. ([#8451](https://github.com/crystal-lang/crystal/pull/8451), thanks @asterite) - Add `Enumerable#each_cons_pair` and `Iterator#cons_pair` yielding a tuple. ([#8332](https://github.com/crystal-lang/crystal/pull/8332), thanks @straight-shoota) - Add `offset` argument to all `map_with_index` methods. ([#8264](https://github.com/crystal-lang/crystal/pull/8264), thanks @asterite) - **(performance)** Optimized version of `Tuple#to_a`. ([#8265](https://github.com/crystal-lang/crystal/pull/8265), thanks @asterite) - Add docs to `Hash.merge!(other : Hash, &)`. ([#8380](https://github.com/crystal-lang/crystal/pull/8380), thanks @jan-zajic) - Add docs to `Hash.select`. ([#8391](https://github.com/crystal-lang/crystal/pull/8391), thanks @jan-zajic) - Add docs and specs to `Enumerable.reduce`. ([#8378](https://github.com/crystal-lang/crystal/pull/8378), thanks @jan-zajic) #### Serialization - **(breaking-change)** Make `XML::Reader#expand` raise, introduce `XML::Reader#expand?` for former behavior. ([#8186](https://github.com/crystal-lang/crystal/pull/8186), thanks @Blacksmoke16) - Allow `JSON.mapping` & `YAML.mapping` converter attribute to be applied to `Array` and `Hash`. ([#8156](https://github.com/crystal-lang/crystal/pull/8156), thanks @rodrigopinto) - Add `use_json_discriminator` and `use_yaml_discriminator` to choose type based on property value. ([#8406](https://github.com/crystal-lang/crystal/pull/8406), thanks @asterite) - Remove return type `self` restriction from `Object.from_json` and `Object.from_yaml`. ([#8489](https://github.com/crystal-lang/crystal/pull/8489), thanks @straight-shoota) #### Files - **(breaking-change)** Remove expand home (`~`) by default in `File.expand_path` and `Path#expand`, now opt-in argument. ([#7903](https://github.com/crystal-lang/crystal/pull/7903), thanks @didactic-drunk) - Fixed bugs in `Path` regarding `#dirname`, `#each_part`, `#each_parent`. ([#8415](https://github.com/crystal-lang/crystal/pull/8415), thanks @jan-zajic) - Fixed `GZip::Reader` and `GZip::Writer` to handle large data sizes. ([#8421](https://github.com/crystal-lang/crystal/pull/8421), thanks @straight-shoota) - Fixed `File::Info#same_file?` by providing access to 64 bit inode numbers. ([#8355](https://github.com/crystal-lang/crystal/pull/8355), thanks @didactic-drunk) #### Networking - Fixed `HTTP::Response#mime_type` returns `nil` on empty `Content-Type` header. ([#8464](https://github.com/crystal-lang/crystal/pull/8464), thanks @Sija) - Fixed handling of unidirectional SSL servers hang. ([#8481](https://github.com/crystal-lang/crystal/pull/8481), thanks @rdp) - Add `HTTP::Client#write_timeout`. ([#8507](https://github.com/crystal-lang/crystal/pull/8507), thanks @Sija) - Updated mime type of `.js` files to `text/javascript` and include `image/webp`. ([#8342](https://github.com/crystal-lang/crystal/pull/8342), thanks @mamantoha) - Refactor websocket protocol GUID string. ([#8339](https://github.com/crystal-lang/crystal/pull/8339), thanks @vlazar) #### Crypto - **(breaking-change)** Enforce single-line results of `OpenSSL::DigestBase#base64digest` via `Base64.strict_encode`. ([#8215](https://github.com/crystal-lang/crystal/pull/8215), thanks @j8r) #### Concurrency - Fixed `Channel` successful sent and raise behavior. ([#8284](https://github.com/crystal-lang/crystal/pull/8284), thanks @firejox) - Fixed `Channel#close` to be thread-safe. ([#8249](https://github.com/crystal-lang/crystal/pull/8249), thanks @firejox) - Fixed `select` with `receive?` and closed channels. ([#8304](https://github.com/crystal-lang/crystal/pull/8304), thanks @bcardiff) - Faster `Mutex` implementation and policy checks. ([#8295](https://github.com/crystal-lang/crystal/pull/8295), [#8563](https://github.com/crystal-lang/crystal/pull/8563), thanks @waj, @ysbaddaden) - **(performance)** Channel internals refactor and optimize. ([#8322](https://github.com/crystal-lang/crystal/pull/8322), [#8497](https://github.com/crystal-lang/crystal/pull/8497), thanks @firejox, @Sija) - Add docs to `Channel#send` and `Channel#close`. ([#8356](https://github.com/crystal-lang/crystal/pull/8356), thanks @lbarasti) - Fixed `Thread#gc_thread_handler` for Windows support. ([#8519](https://github.com/crystal-lang/crystal/pull/8519), thanks @straight-shoota) #### System - Don't close pipes used for signal handlers in multi-thread mode. ([#8465](https://github.com/crystal-lang/crystal/pull/8465), thanks @waj) - Fixed thread initialization on OpenBSD. ([#8293](https://github.com/crystal-lang/crystal/pull/8293), thanks @wmoxam) - Implement fibers for win32. ([#7995](https://github.com/crystal-lang/crystal/pull/7995), [#8513](https://github.com/crystal-lang/crystal/pull/8513), thanks @straight-shoota, @firejox) #### Runtime - Fixed fiber initialization on `-Dgc_none -Dpreview_mt`. ([#8280](https://github.com/crystal-lang/crystal/pull/8280), thanks @bcardiff) - Add GC profiling stats and warning bindings. ([#8281](https://github.com/crystal-lang/crystal/pull/8281), thanks @bcardiff, @benoist) - Refactor `callstack_spec`. ([#8308](https://github.com/crystal-lang/crystal/pull/8308), [#8395](https://github.com/crystal-lang/crystal/pull/8395), thanks @straight-shoota, @Sija) #### Spec - Fixed `--fail-fast` behaviour. ([#8453](https://github.com/crystal-lang/crystal/pull/8453), thanks @asterite) - Add before, after, and around hooks. ([#8302](https://github.com/crystal-lang/crystal/pull/8302), thanks @asterite) - Restrict the type returned by `should_not be_nil` and others. ([#8412](https://github.com/crystal-lang/crystal/pull/8412), thanks @asterite) - Add ability to randomize specs via `--order random|`. ([#8310](https://github.com/crystal-lang/crystal/pull/8310), thanks @Fryguy) - Add specs for `Spec` filters. ([#8242](https://github.com/crystal-lang/crystal/pull/8242), thanks @Fryguy) - Add ability to tag specs. ([#8068](https://github.com/crystal-lang/crystal/pull/8068), thanks @Fryguy) ### Compiler - Fixed musl libc detection (Alpine 3.10 regression bug). ([#8330](https://github.com/crystal-lang/crystal/pull/8330), thanks @straight-shoota) - Fixed pragmas handling in macros. ([#8256](https://github.com/crystal-lang/crystal/pull/8256), thanks @asterite) - Fixed parser crash for 'alias Foo?'. ([#8282](https://github.com/crystal-lang/crystal/pull/8282), thanks @oprypin) - Fixed parser error on newline before closing parenthesis. ([#8320](https://github.com/crystal-lang/crystal/pull/8320), thanks @MakeNowJust) - Fixed generic subtypes edge cases triggering `no target defs` error. ([#8417](https://github.com/crystal-lang/crystal/pull/8417), thanks @asterite) - Fixed cleanup of local vars reachable by macros. ([#8529](https://github.com/crystal-lang/crystal/pull/8529), thanks @asterite) - Add support for LLVM 9. ([#8358](https://github.com/crystal-lang/crystal/pull/8358), thanks @RX14) - Add `--mcmodel` option to compiler. ([#8363](https://github.com/crystal-lang/crystal/pull/8363), thanks @ffwff) - Disallow `instance_sizeof` on union. ([#8399](https://github.com/crystal-lang/crystal/pull/8399), thanks @asterite) - Add mention to `crystal --help` in help. ([#3628](https://github.com/crystal-lang/crystal/pull/3628), thanks @rdp) - Improve error message when a filename is misspelled. ([#8500](https://github.com/crystal-lang/crystal/pull/8500), thanks @rdp) - Show full path of locally compiled Crystal. ([#8486](https://github.com/crystal-lang/crystal/pull/8486), thanks @rdp) - Code cleanups. ([#8460](https://github.com/crystal-lang/crystal/pull/8460), thanks @veelenga) #### Language semantics - Fixed method lookup priority when type alias of union is used. ([#8258](https://github.com/crystal-lang/crystal/pull/8258), thanks @asterite) - Fixed visibility modifiers in virtual types. ([#8562](https://github.com/crystal-lang/crystal/pull/8562), thanks @asterite) - Fixed `sizeof(Bool)`. ([#8273](https://github.com/crystal-lang/crystal/pull/8273), thanks @asterite) ### Tools #### Formatter - Fixed indent in arguments. ([#8315](https://github.com/crystal-lang/crystal/pull/8315), thanks @MakeNowJust) - Fixed crash related to parenthesis on generic types. ([#8501](https://github.com/crystal-lang/crystal/pull/8501), thanks @asterite) #### Doc generator - Fixed underscore type restriction in doc generator. ([#8331](https://github.com/crystal-lang/crystal/pull/8331), thanks @straight-shoota) - Correctly attach docs through multiple macro invocations. ([#8502](https://github.com/crystal-lang/crystal/pull/8502), thanks @asterite) - Allow constants to use `:ditto:`. ([#8389](https://github.com/crystal-lang/crystal/pull/8389), thanks @Blacksmoke16) - Add sitemap generator. ([#8348](https://github.com/crystal-lang/crystal/pull/8348), thanks @straight-shoota) - Add documentation for pseudo-methods: `!`, `as`, `nil?`, etc.. ([#8327](https://github.com/crystal-lang/crystal/pull/8327), [#8371](https://github.com/crystal-lang/crystal/pull/8371), thanks @straight-shoota) - Add clickable anchor icon next to headings. ([#8344](https://github.com/crystal-lang/crystal/pull/8344), thanks @Blacksmoke16) - Use `&` instead of `&block` for signature of yielding method. ([#8394](https://github.com/crystal-lang/crystal/pull/8394), thanks @j8r) #### Playground - Do not collapse whitespaces in playground sidebar. ([#8528](https://github.com/crystal-lang/crystal/pull/8528), thanks @hugopl) ### Others - CI improvements and housekeeping. ([#8210](https://github.com/crystal-lang/crystal/pull/8210), [#8251](https://github.com/crystal-lang/crystal/pull/8251), [#8283](https://github.com/crystal-lang/crystal/pull/8283), [#8439](https://github.com/crystal-lang/crystal/pull/8439), [#8510](https://github.com/crystal-lang/crystal/pull/8510), thanks @bcardiff) - Update base docker images to `bionic` and LLVM 8.0. ([#8442](https://github.com/crystal-lang/crystal/pull/8442), thanks @bcardiff) - Repository clean-up. ([#8312](https://github.com/crystal-lang/crystal/pull/8312), [#8397](https://github.com/crystal-lang/crystal/pull/8397), thanks @bcardiff, @straight-shoota) ## 0.31.1 (2019-09-30) ### Standard library #### Numeric - Fixed overflow in `Random::Secure`. ([#8224](https://github.com/crystal-lang/crystal/pull/8224), thanks @oprypin) #### Networking - Workaround `IO::Evented#evented_write` invalid `IndexError` error. ([#8239](https://github.com/crystal-lang/crystal/pull/8239), thanks @bcardiff) #### Concurrency - Use bdw-gc upstream patch for green threads support. ([#8225](https://github.com/crystal-lang/crystal/pull/8225), thanks @bcardiff) - Refactor `Channel` to use records instead of tuples. ([#8227](https://github.com/crystal-lang/crystal/pull/8227), thanks @asterite) #### Spec - Add `before_suite` and `after_suite` hooks. ([#8238](https://github.com/crystal-lang/crystal/pull/8238), thanks @asterite) ### Compiler - Fix debug location information when emitting main code from module. ([#8234](https://github.com/crystal-lang/crystal/pull/8234), thanks @asterite) #### Language semantics - Use virtual type for `uninitialized`. ([#8221](https://github.com/crystal-lang/crystal/pull/8221), thanks @asterite) ## 0.31.0 (2019-09-23) ### Language changes - Allow non-captured block args with type restriction using `& : T -> U`. ([#8117](https://github.com/crystal-lang/crystal/pull/8117), thanks @asterite) #### Macros - Ensure `@type` is devirtualized inside macros. ([#8149](https://github.com/crystal-lang/crystal/pull/8149), thanks @asterite) ### Standard library - **(breaking-change)** Remove `Markdown` from the std-lib. ([#8115](https://github.com/crystal-lang/crystal/pull/8115), thanks @asterite) - **(breaking-change)** Deprecate `OptionParser#parse!`, use `OptionParser#parse`. ([#8041](https://github.com/crystal-lang/crystal/pull/8041), thanks @didactic-drunk) - Fix example codes in multiple places. ([#8194](https://github.com/crystal-lang/crystal/pull/8194), thanks @maiha) #### Numeric - **(breaking-change)** Enable overflow by default. ([#8170](https://github.com/crystal-lang/crystal/pull/8170), thanks @bcardiff) - **(breaking-change)** Make `/` the arithmetic division for all types. ([#8120](https://github.com/crystal-lang/crystal/pull/8120), thanks @bcardiff) - Add `BigDecimal#**` and `BigRational#**` (pow operator). ([#7860](https://github.com/crystal-lang/crystal/pull/7860), thanks @jwbuiter) - Avoid overflow exception in `Number#round(digits, base)`. ([#8204](https://github.com/crystal-lang/crystal/pull/8204), thanks @bcardiff) - Refactor `Int#divisible_by?` for clarity. ([#8045](https://github.com/crystal-lang/crystal/pull/8045), thanks @yxhuvud) #### Text - **(performance)** Minor `String#lchop?` ASCII-only optimization. ([#8052](https://github.com/crystal-lang/crystal/pull/8052), thanks @r00ster91) #### Collections - **(performance)** Array optimizations for small number of elements. ([#8048](https://github.com/crystal-lang/crystal/pull/8048), thanks @asterite) - **(performance)** Optimize `Array#*`. ([#8087](https://github.com/crystal-lang/crystal/pull/8087), thanks @asterite) - **(performance)** Hash now uses an open addressing algorithm. ([#8017](https://github.com/crystal-lang/crystal/pull/8017), [#8182](https://github.com/crystal-lang/crystal/pull/8182), thanks @asterite) - **(performance)** Optimize `Hash#to_a`, `Hash#keys` and `Hash#values`. ([#8042](https://github.com/crystal-lang/crystal/pull/8042), thanks @asterite) - **(performance)** Add `Hash#put` and optimize `Set#add?`. ([#8116](https://github.com/crystal-lang/crystal/pull/8116), thanks @asterite) - Fixed `Slice#==` for some generic instantiations, add `Slice#<=>`. ([#8074](https://github.com/crystal-lang/crystal/pull/8074), thanks @asterite) - Add docs on idempotence and methods involving eager evaluation in `Iterator`. ([#8053](https://github.com/crystal-lang/crystal/pull/8053), thanks @KimBurgess) - Add `Set#+`. ([#8121](https://github.com/crystal-lang/crystal/pull/8121), thanks @sam0x17) - Refactor `Hash` to use integer division instead of float division. ([#8104](https://github.com/crystal-lang/crystal/pull/8104), thanks @asterite) #### Serialization - **(breaking-change)** Rename `XML::Type` to `XML::Node::Type`, introduce `XML::Reader::Type`. ([#8134](https://github.com/crystal-lang/crystal/pull/8134), thanks @asterite) - Fixed JSON and YAML parsing of `NamedTuple` with nilable fields. ([#8109](https://github.com/crystal-lang/crystal/pull/8109), thanks @asterite) - Fixed YAML to emit unicode characters as such. ([#8132](https://github.com/crystal-lang/crystal/pull/8132), thanks @asterite) - Fixed INI generation of empty sections. ([#8106](https://github.com/crystal-lang/crystal/pull/8106), thanks @j8r) #### Files - **(performance)** Optimize `Path#join` by precomputing capacity if possible. ([#8078](https://github.com/crystal-lang/crystal/pull/8078), thanks @asterite) - **(performance)** Optimize `Path#join` for the case of joining one single part. ([#8082](https://github.com/crystal-lang/crystal/pull/8082), thanks @asterite) - **(performance)** Optimize `Dir.glob`. ([#8081](https://github.com/crystal-lang/crystal/pull/8081), thanks @asterite) - Fixed `File.basename` off-by-one corner-case. ([#8119](https://github.com/crystal-lang/crystal/pull/8119), thanks @ysbaddaden) - Fixed unneeded evaluation of `Path.home` on `Path.expand`. ([#8128](https://github.com/crystal-lang/crystal/pull/8128), thanks @asterite) - Fixed `Zip::Writer` STORED compression. ([#8142](https://github.com/crystal-lang/crystal/pull/8142), thanks @asterite) - Fixed missing check on `ARGF` if read_count is zero. ([#8177](https://github.com/crystal-lang/crystal/pull/8177), thanks @Blacksmoke16) #### Networking - **(breaking-change)** Replace `HTTP::Server::Response#respond_with_error` with `#respond_with_status`. ([#6988](https://github.com/crystal-lang/crystal/pull/6988), thanks @straight-shoota) - **(breaking-change)** Handle too long URIs and too large header fields in `HTTP::Request.from_io` and remove `HTTP::Request::BadRequest`. ([#8013](https://github.com/crystal-lang/crystal/pull/8013), thanks @straight-shoota) - Fixed memory leak from `SSL_new` if `ssl_accept` fails. ([#8088](https://github.com/crystal-lang/crystal/pull/8088), thanks @rdp) - Fixed WebSocket ipv6 hostname connection. ([#8066](https://github.com/crystal-lang/crystal/pull/8066), thanks @MrSorcus) - Add `URI#query_params` method. ([#8090](https://github.com/crystal-lang/crystal/pull/8090), thanks @rodrigopinto) - Add `URI#resolve` and `URI#relativize`. ([#7716](https://github.com/crystal-lang/crystal/pull/7716), thanks @straight-shoota) - Add `#clear`, `#delete`, and `#size` methods to `HTTP::Cookies`. ([#8107](https://github.com/crystal-lang/crystal/pull/8107), thanks @sam0x17) - Refactor `http/server_spec`. ([#8056](https://github.com/crystal-lang/crystal/pull/8056), thanks @straight-shoota) - Refactor UDP specs to use random port. ([#8139](https://github.com/crystal-lang/crystal/pull/8139), thanks @waj) #### Concurrency - Multithreading. ([#8112](https://github.com/crystal-lang/crystal/pull/8112), thanks @waj) - Delay releasing of fiber stack in multi-thread mode. ([#8138](https://github.com/crystal-lang/crystal/pull/8138), thanks @waj) - Make `Crystal::Scheduler.init_workers` block until workers are ready. ([#8145](https://github.com/crystal-lang/crystal/pull/8145), thanks @bcardiff) - Make `Crystal::ThreadLocalValue` thread-safe. ([#8168](https://github.com/crystal-lang/crystal/pull/8168), thanks @waj) - Let `exec_recursive` use a thread-local data structure. ([#8146](https://github.com/crystal-lang/crystal/pull/8146), thanks @asterite) - Add explicit return types for some channel methods. ([#8161](https://github.com/crystal-lang/crystal/pull/8161), thanks @Blacksmoke16) - Remove the dedicated fiber to run the event loop. ([#8173](https://github.com/crystal-lang/crystal/pull/8173), thanks @waj) - Fix corruption of thread linked list. ([#8196](https://github.com/crystal-lang/crystal/pull/8196), thanks @waj) - Workaround compile on win32 until fibers is implemented. ([#8195](https://github.com/crystal-lang/crystal/pull/8195), thanks @straight-shoota) #### System - Increase precision of `Process.times`. ([#8097](https://github.com/crystal-lang/crystal/pull/8097), thanks @jgaskins) #### Spec - **(breaking-change)** Add support for `focus`. ([#8125](https://github.com/crystal-lang/crystal/pull/8125), [#8178](https://github.com/crystal-lang/crystal/pull/8178), [#8208](https://github.com/crystal-lang/crystal/pull/8208), thanks @asterite, @straight-shoota, @bcardiff) ### Compiler - Fixed ICE on declarations inside fun. ([#8076](https://github.com/crystal-lang/crystal/pull/8076), thanks @asterite) - Fixed missing `name_location` of some calls. ([#8192](https://github.com/crystal-lang/crystal/pull/8192), thanks @asterite) - Activate compiler warnings by default. ([#8171](https://github.com/crystal-lang/crystal/pull/8171), thanks @bcardiff) - Improve return type mismatch error. ([#8203](https://github.com/crystal-lang/crystal/pull/8203), thanks @asterite) - Improve `for` expression error. ([#7641](https://github.com/crystal-lang/crystal/pull/7641), thanks @r00ster91) #### Language semantics - Fixed abstract def check regarding generic ancestor lookup. ([#8098](https://github.com/crystal-lang/crystal/pull/8098), thanks @asterite) - Fixed missing virtualization of type arguments in `Proc` types. ([#8159](https://github.com/crystal-lang/crystal/pull/8159), thanks @asterite) - Fixed incorrect typing after exception handler. ([#8037](https://github.com/crystal-lang/crystal/pull/8037), thanks @asterite) - Fixed behaviour when a yield node can't be typed. ([#8101](https://github.com/crystal-lang/crystal/pull/8101), thanks @asterite) - Fixed `offsetof` on reference types. ([#8137](https://github.com/crystal-lang/crystal/pull/8137), thanks @mcr431) - Allow rescue var to be closured. ([#8143](https://github.com/crystal-lang/crystal/pull/8143), thanks @asterite) - Refactor class var and constant initialization. ([#8067](https://github.com/crystal-lang/crystal/pull/8067), [#8091](https://github.com/crystal-lang/crystal/pull/8091), thanks @waj) - Add runtime check for recursive initialization of class variables and constants. ([#8172](https://github.com/crystal-lang/crystal/pull/8172), thanks @waj) ### Tools #### Doc generator - Fixed link to constructors of another class. ([#8110](https://github.com/crystal-lang/crystal/pull/8110), thanks @asterite) - Enable docs from previous def and/or ancestors to be inherited. ([#6989](https://github.com/crystal-lang/crystal/pull/6989), thanks @asterite) ### Others - Update CI to use 0.30.1. ([#8032](https://github.com/crystal-lang/crystal/pull/8032), thanks @bcardiff) - Use LLVM 8.0 for Linux official packages. ([#8155](https://github.com/crystal-lang/crystal/pull/8155), thanks @bcardiff, @RX14) - Update dependencies of the build process. ([#8205](https://github.com/crystal-lang/crystal/pull/8205), thanks @bcardiff) - Code cleanups. ([#8033](https://github.com/crystal-lang/crystal/pull/8033), thanks @straight-shoota) ## 0.30.1 (2019-08-12) ### Standard library #### Numeric - Fixed `Number#humanize` digits. ([#8027](https://github.com/crystal-lang/crystal/pull/8027), thanks @straight-shoota) #### Networking - Fixed TCP socket leaking after failed SSL connect in `HTTP::Client#socket`. ([#8025](https://github.com/crystal-lang/crystal/pull/8025), thanks @straight-shoota) - Honor normalized header names for HTTP requests. ([#8061](https://github.com/crystal-lang/crystal/pull/8061), thanks @asterite) #### Concurrency - Don't resume fibers directly from event loop callbacks (or support for libevent 2.1.11). ([#8058](https://github.com/crystal-lang/crystal/pull/8058), thanks @waj) ### Compiler - Fixed `sizeof(Nil)` and other empty types. ([#8040](https://github.com/crystal-lang/crystal/pull/8040), thanks @asterite) - Avoid internal globals of type i128 or u128. (or workaround [a llvm 128 bits bug](https://bugs.llvm.org/show_bug.cgi?id=42932)). ([#8063](https://github.com/crystal-lang/crystal/pull/8063), thanks @bcardiff, @asterite) #### Language semantics - Consider abstract method implementation in supertype for abstract method checks. ([#8035](https://github.com/crystal-lang/crystal/pull/8035), thanks @asterite) ### Tools #### Formatter - Handle consecutive macro literals when subformatting. ([#8034](https://github.com/crystal-lang/crystal/pull/8034), thanks @asterite) - Fixed crash when formatting syntax error inside macro. ([#8055](https://github.com/crystal-lang/crystal/pull/8055), thanks @asterite) ### Others - Use LLVM 6.0.1 for darwin official packages. ([#7994](https://github.com/crystal-lang/crystal/pull/7994), thanks @bcardiff) - Split std_specs in 32 bits CI. ([#8065](https://github.com/crystal-lang/crystal/pull/8065), thanks @bcardiff) ## 0.30.0 (2019-08-01) ### Language changes - **(breaking-change)** Enforce abstract methods return types. ([#7956](https://github.com/crystal-lang/crystal/pull/7956), [#7999](https://github.com/crystal-lang/crystal/pull/7999), [#8010](https://github.com/crystal-lang/crystal/pull/8010), thanks @asterite) - **(breaking-change)** Don't allow ranges to span across lines. ([#7888](https://github.com/crystal-lang/crystal/pull/7888), thanks @oprypin) #### Macros - Add `args`/`named_args` macro methods to `Annotations`. ([#7694](https://github.com/crystal-lang/crystal/pull/7694), thanks @Blacksmoke16) - Unify `resolve` and `types` macro methods API for `Type` and `Path` for convenience. ([#7970](https://github.com/crystal-lang/crystal/pull/7970), thanks @asterite) ### Standard library - **(breaking-change)** Remove `UUID#to_slice` in favor of `UUID#bytes` to fix dangling pointer issues. ([#7901](https://github.com/crystal-lang/crystal/pull/7901), thanks @ysbaddaden) - **(performance)** Improve `Box` of reference types. ([#8016](https://github.com/crystal-lang/crystal/pull/8016), thanks @waj) - Fixed initial seed of `Random::ISAAC`. ([#7977](https://github.com/crystal-lang/crystal/pull/7977), thanks @asterite) - Fixed mem intrinsics for aarch64. ([#7983](https://github.com/crystal-lang/crystal/pull/7983), thanks @drujensen) - Add `Benchmark.memory`. ([#7835](https://github.com/crystal-lang/crystal/pull/7835), thanks @r00ster91) - Allow setting default capacity for `StringPool`. ([#7899](https://github.com/crystal-lang/crystal/pull/7899), thanks @carlhoerberg) - Add type restrictions to `INI`. ([#7831](https://github.com/crystal-lang/crystal/pull/7831), thanks @j8r) - Fixed `Logger` docs. ([#7898](https://github.com/crystal-lang/crystal/pull/7898), thanks @dprobinson) - Fix example codes in multiple places. ([#8003](https://github.com/crystal-lang/crystal/pull/8003), thanks @maiha) #### Numeric - Fixed incorrect `Int#%` overflow. ([#7980](https://github.com/crystal-lang/crystal/pull/7980), thanks @asterite) - Fixed inconsistency between `Float#to_s` and `BigFloat#to_s`, always show `.0` for whole numbers. ([#7982](https://github.com/crystal-lang/crystal/pull/7982), thanks @Lasvad) #### Text - Fixed unicode alternate ranges generation. ([#7924](https://github.com/crystal-lang/crystal/pull/7924), thanks @asterite) #### Collections - Add `Enumerable#tally`. ([#7921](https://github.com/crystal-lang/crystal/pull/7921), thanks @kachick) - Add `Enumerable#reduce?` overload with not initial value. ([#7941](https://github.com/crystal-lang/crystal/pull/7941), thanks @miketheman) - Fix specs of `Enumerable#min_by?`. ([#7919](https://github.com/crystal-lang/crystal/pull/7919), thanks @kachick) #### Serialization - **(breaking-change)** JSON: use enums instead of symbols. ([#7966](https://github.com/crystal-lang/crystal/pull/7966), thanks @asterite) - Fixed YAML deserialization of String in a union type. ([#7938](https://github.com/crystal-lang/crystal/pull/7938), thanks @asterite) - Validate element names in `XML::Builder`. ([#7965](https://github.com/crystal-lang/crystal/pull/7965), thanks @Blacksmoke16) - Allow numeric keys in JSON (ie: `Hash(Int32, String).from_json`). ([#7944](https://github.com/crystal-lang/crystal/pull/7944), thanks @asterite) - Add `alias`/`merge` methods to `YAML::Builder` and `YAML::Nodes::Builder`. ([#7949](https://github.com/crystal-lang/crystal/pull/7949), thanks @Blacksmoke16) #### Files - Adds `File.readlink` to match `File.symlink`. ([#7858](https://github.com/crystal-lang/crystal/pull/7858), thanks @didactic-drunk) #### Networking - **(breaking-change)** Improve URL encoding. `URI.escape` and `URI.unescape` are renamed to `URI.encode_www_form` and `URI.decode_www_form`. Add `URI.encode` and `URI.decode`. ([#7997](https://github.com/crystal-lang/crystal/pull/7997), [#8021](https://github.com/crystal-lang/crystal/pull/8021), thanks @straight-shoota, @bcardiff) - **(performance)** HTTP protocol parsing optimizations. ([#8002](https://github.com/crystal-lang/crystal/pull/8002), [#8009](https://github.com/crystal-lang/crystal/pull/8009), thanks @asterite) - Fixed `HTTP::Server` response double-close. ([#7908](https://github.com/crystal-lang/crystal/pull/7908), thanks @asterite) - Enforce `HTTP::Client` host argument is just a host. ([#7958](https://github.com/crystal-lang/crystal/pull/7958), thanks @asterite) - Allow `HTTP::Params.encode` to encode an arrays of values for a key. ([#7862](https://github.com/crystal-lang/crystal/pull/7862), thanks @rodrigopinto) - Forward `read_timeout`/`write_timeout` in ssl socket to underlying socket. ([#7820](https://github.com/crystal-lang/crystal/pull/7820), thanks @carlhoerberg) - Natively support [Same-site Cookies](https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1.1). ([#7864](https://github.com/crystal-lang/crystal/pull/7864), thanks @Blacksmoke16) - Allow setting buffer size for `IO::Buffered`. ([#7930](https://github.com/crystal-lang/crystal/pull/7930), thanks @carlhoerberg) #### Crypto - Require openssl algorithm in pkcs5. ([#7985](https://github.com/crystal-lang/crystal/pull/7985), thanks @will) - Fixed cipher expectation in `OpenSSL::SSL::Socket` spec. ([#7871](https://github.com/crystal-lang/crystal/pull/7871), thanks @j8r) #### Concurrency - Fixed `sysconf` call on OpenBSD. ([#7879](https://github.com/crystal-lang/crystal/pull/7879), thanks @jcs) #### System - Introduce `System::User` and `System::Group`. ([#7725](https://github.com/crystal-lang/crystal/pull/7725), thanks @woodruffw, @chris-huxtable) - Add docs for `Process::Status.exit_status` (#7873). ([#8014](https://github.com/crystal-lang/crystal/pull/8014), thanks @UlisseMini) ### Compiler - Fixed codegen of `pointer.as(Nil)`. ([#8019](https://github.com/crystal-lang/crystal/pull/8019), thanks @asterite) - Fixed edge cases in parser and stringifier. ([#7886](https://github.com/crystal-lang/crystal/pull/7886), thanks @oprypin) - Fixed `concrete_types` for virtual metaclass and modules. ([#7951](https://github.com/crystal-lang/crystal/pull/7951), thanks @bcardiff) - Fixed incorrect `remove_indirection` in `TypeDefType`. ([#7971](https://github.com/crystal-lang/crystal/pull/7971), thanks @bcardiff) - Fixed missing `CRYSTAL_SPEC_COMPILER_FLAGS` usage in some more specs. ([774768](https://github.com/crystal-lang/crystal/commit/77476800836eb47c8d783e2259bf21c2992f2041), thanks @bcardiff) - Revamp compile error formatting & output. ([#7748](https://github.com/crystal-lang/crystal/pull/7748), thanks @martimatix) - Add support for LLVM 8. ([#7987](https://github.com/crystal-lang/crystal/pull/7987), thanks @bcardiff) - Add support for LLVM 7. ([#7986](https://github.com/crystal-lang/crystal/pull/7986), thanks @bcardiff, @waj, @foutrelis, @wmoxam) - Add debug log helper function for codegen. ([#7935](https://github.com/crystal-lang/crystal/pull/7935), [#7937](https://github.com/crystal-lang/crystal/pull/7937), thanks @bcardiff) - Refactor codegen of unions. ([#7940](https://github.com/crystal-lang/crystal/pull/7940), thanks @bcardiff) - Move `LLVMId` from `CodeGenVisitor` to `Program`. ([#7973](https://github.com/crystal-lang/crystal/pull/7973), thanks @bcardiff) - Minor additions and refactors on for LLVM codegen. ([#7972](https://github.com/crystal-lang/crystal/pull/7972), thanks @bcardiff) - Add `bin/check-compiler-flag` helper script. Add `make clean_cache`. ([da3892](https://github.com/crystal-lang/crystal/commit/da38927f3a00f1e6e5ea86b96ca669533f0aa438), thanks @bcardiff) #### Language semantics - Fixed generic metaclass argument expansion. ([#7916](https://github.com/crystal-lang/crystal/pull/7916), thanks @asterite) - Fixed top-level private const not being scoped. ([#7907](https://github.com/crystal-lang/crystal/pull/7907), thanks @asterite) - Fixed enum overflow when declaring members. ([#7881](https://github.com/crystal-lang/crystal/pull/7881), thanks @asterite) - Fixed annotation lookup on generic types. ([#7891](https://github.com/crystal-lang/crystal/pull/7891), thanks @asterite) ### Tools #### Formatter - Format top-level inline macros. ([#7889](https://github.com/crystal-lang/crystal/pull/7889), [#7992](https://github.com/crystal-lang/crystal/pull/7992), thanks @asterite) #### Doc generator - Allow rendering tags on methods without any docs. ([#7952](https://github.com/crystal-lang/crystal/pull/7952), thanks @Blacksmoke16) ### Others - Update CI to use 0.29.0. ([#7863](https://github.com/crystal-lang/crystal/pull/7863), thanks @bcardiff) - Automated snap publishing. ([#7893](https://github.com/crystal-lang/crystal/pull/7893), thanks @bcardiff) - ~~Use LLVM 6.0.1 for darwin official packages.~~ ([#7994](https://github.com/crystal-lang/crystal/pull/7994), thanks @bcardiff) ## 0.29.0 (2019-06-05) ### Standard library - Fix example codes in multiple places. ([#7718](https://github.com/crystal-lang/crystal/pull/7718), thanks @maiha) #### Macros - Fix inheritance support of `record` macro. ([#7811](https://github.com/crystal-lang/crystal/pull/7811), thanks @asterite) - Omit quotes in `puts` macro output. ([#7734](https://github.com/crystal-lang/crystal/pull/7734), thanks @asterite) #### Numeric - **(performance)** Optimize `String#to_u` methods for the case of a negative number. ([#7446](https://github.com/crystal-lang/crystal/pull/7446), thanks @r00ster91) #### Text - **(breaking-change)** Deprecate `String#at`, use `String#char_at`. ([#7633](https://github.com/crystal-lang/crystal/pull/7633), thanks @j8r) - **(breaking-change)** Change `String#to_i` to parse octals with prefix `0o` (but not `0` by default). ([#7691](https://github.com/crystal-lang/crystal/pull/7691), thanks @icy-arctic-fox) - **(breaking-change)** Restrict some `String#to_i` arguments to be `Bool`. ([#7436](https://github.com/crystal-lang/crystal/pull/7436), thanks @j8r) - Add `downcase` option to `String#camelcase`. ([#7717](https://github.com/crystal-lang/crystal/pull/7717), thanks @wontruefree) - Add support for unicode 12.0.0. ([#7721](https://github.com/crystal-lang/crystal/pull/7721), thanks @Blacksmoke16) - Fix `Unicode` not showing up in the API docs. ([#7720](https://github.com/crystal-lang/crystal/pull/7720), thanks @r00ster91) #### Collections - **(breaking-change)** Remove `Slice#pointer`. ([#7581](https://github.com/crystal-lang/crystal/pull/7581), thanks @Maroo-b) - Add sort methods to `Slice`. ([#7597](https://github.com/crystal-lang/crystal/pull/7597), thanks @Maroo-b) - Add `Slice#[]?`. ([#7701](https://github.com/crystal-lang/crystal/pull/7701), thanks @Sija) - Improve docs for `Slice#[]`. ([#7780](https://github.com/crystal-lang/crystal/pull/7780), thanks @Sija) #### Serialization - YAML: let String handle numbers too. ([#7809](https://github.com/crystal-lang/crystal/pull/7809), thanks @asterite) #### Time - Fix time format RFC 3339 to not include offset seconds. ([#7492](https://github.com/crystal-lang/crystal/pull/7492), thanks @straight-shoota) #### Files - **(breaking-change)** Rename `File::DEVNULL` to `File::NULL`. ([#7778](https://github.com/crystal-lang/crystal/pull/7778), thanks @r00ster91) - Fix handling of files starting with `~` in `Path#expand`. ([#7768](https://github.com/crystal-lang/crystal/pull/7768), thanks @byroot) - Fix `Dir.glob(match_hidden: false)` not hiding hidden files properly. ([#7774](https://github.com/crystal-lang/crystal/pull/7774), thanks @ayazhafiz) #### Networking - **(breaking-change)** Let `IO#copy` return `UInt64`. ([#7660](https://github.com/crystal-lang/crystal/pull/7660), thanks @asterite) - Add support for UDP multicast. ([#7423](https://github.com/crystal-lang/crystal/pull/7423), thanks @stakach) - Add missing requires to `openssl.cr`. ([#7803](https://github.com/crystal-lang/crystal/pull/7803), thanks @RX14) - Add `IO::MultiWriter#flush`. ([#7765](https://github.com/crystal-lang/crystal/pull/7765), thanks @mamantoha) - Add `OpenSSL::SSL::Socket#cipher` and `#tls_version`. ([#7445](https://github.com/crystal-lang/crystal/pull/7445), thanks @carlhoerberg) - Improve `URI#normalize`. ([#7635](https://github.com/crystal-lang/crystal/pull/7635), thanks @straight-shoota) - Improve documentation of some `URI` methods. ([#7796](https://github.com/crystal-lang/crystal/pull/7796), thanks @r00ster91) - Refactor `StaticFileHandler` specs for `Last-Modified` header. ([#7640](https://github.com/crystal-lang/crystal/pull/7640), thanks @straight-shoota) - Refactor compression usage in handler specs. ([#7819](https://github.com/crystal-lang/crystal/pull/7819), thanks @asterite) #### Crypto - **(breaking-change)** Rename `Crypto::Bcrypt::Password#==` to `#verify`. ([#7790](https://github.com/crystal-lang/crystal/pull/7790), thanks @asterite) #### Concurrency - Add docs for `Channel`. ([#7673](https://github.com/crystal-lang/crystal/pull/7673), thanks @j8r) ### Compiler - **(breaking-change)** Fix require relative path resolution. ([#7758](https://github.com/crystal-lang/crystal/pull/7758), thanks @asterite) - **(breaking-change)** Disallow '!' or '?' at the end of the LHS in an assignment. ([#7582](https://github.com/crystal-lang/crystal/pull/7582), thanks @Maroo-b) - Allow running compiler_specs with specific flags. ([#7837](https://github.com/crystal-lang/crystal/pull/7837), thanks @bcardiff) - Fix extend from generic types. ([#7812](https://github.com/crystal-lang/crystal/pull/7812), thanks @asterite) - Don't virtualize types in `Union(...)` and keep more accurate type information. ([#7815](https://github.com/crystal-lang/crystal/pull/7815), thanks @asterite) - Do not generate debug metadata for arguments of naked functions. ([#7775](https://github.com/crystal-lang/crystal/pull/7775), thanks @eyusupov) - Detect deprecation on initialize methods and methods with named args. ([#7724](https://github.com/crystal-lang/crystal/pull/7724), thanks @bcardiff) - Fix track of AST nodes location. ([#7827](https://github.com/crystal-lang/crystal/pull/7827), thanks @asterite) - Fix `offsetof` not being usable with macros. ([#7703](https://github.com/crystal-lang/crystal/pull/7703), thanks @malte-v) - Allow parsing of `call &.@ivar`. ([#7754](https://github.com/crystal-lang/crystal/pull/7754), thanks @asterite) - Fix `Def#to_s` with `**options` and `&block`. ([#7854](https://github.com/crystal-lang/crystal/pull/7854), thanks @MakeNowJust) - Check `pointerof` inner expression for errors. ([#7755](https://github.com/crystal-lang/crystal/pull/7755), thanks @asterite) - Fix some error messages. ([#7833](https://github.com/crystal-lang/crystal/pull/7833), thanks @asterite) - Improve wording of `pointerof(self)` parser error. ([#7542](https://github.com/crystal-lang/crystal/pull/7542), thanks @r00ster91) - Fix typo. ([#7828](https://github.com/crystal-lang/crystal/pull/7828), thanks @RX14) #### Language semantics - **(breaking-change)** Fix new/initialize lookup regarding modules. ([#7818](https://github.com/crystal-lang/crystal/pull/7818), thanks @asterite) - **(breaking-change)** Don't precompute `sizeof` on abstract structs and modules. ([#7801](https://github.com/crystal-lang/crystal/pull/7801), thanks @asterite) - Consider macro calls in `@ivar` initializer. ([#7750](https://github.com/crystal-lang/crystal/pull/7750), thanks @asterite) - Give precedence to `T.class` over `Class` in method lookup. ([#7759](https://github.com/crystal-lang/crystal/pull/7759), thanks @asterite) - Honor enum base type on non-default values. ([#7776](https://github.com/crystal-lang/crystal/pull/7776), thanks @asterite) - Avoid lookup of private def defined inside macro. ([#7733](https://github.com/crystal-lang/crystal/pull/7733), thanks @asterite) - Improve type flow of var in `if` with `&&`. ([#7785](https://github.com/crystal-lang/crystal/pull/7785), thanks @asterite) - Fix handling of `NoReturn` in `if`. ([#7792](https://github.com/crystal-lang/crystal/pull/7792), thanks @asterite) - Improve edge issues with `while` and `rescue`. ([#7806](https://github.com/crystal-lang/crystal/pull/7806), thanks @asterite) - Improve error on macro call in proc pointer. ([#7757](https://github.com/crystal-lang/crystal/pull/7757), thanks @asterite) - Fix error on named args forwarding. ([#7756](https://github.com/crystal-lang/crystal/pull/7756), thanks @asterite) - Check `NoReturn` type in named args. ([#7761](https://github.com/crystal-lang/crystal/pull/7761), thanks @asterite) - Fix internal handling of unbound/abstract generic types. ([#7781](https://github.com/crystal-lang/crystal/pull/7781), thanks @asterite) - Fix wrong cast to unbound generic type. ([#7793](https://github.com/crystal-lang/crystal/pull/7793), thanks @asterite) - Fix subclass observer to handle edge case call over generic types. ([#7735](https://github.com/crystal-lang/crystal/pull/7735), thanks @asterite) - Fix edge case of abstract struct with one subclass. ([#7787](https://github.com/crystal-lang/crystal/pull/7787), thanks @asterite) - Make automatic cast work with `with ... yield`. ([#7746](https://github.com/crystal-lang/crystal/pull/7746), thanks @asterite) ### Tools - Allow to lookup class and module implementations. ([#7742](https://github.com/crystal-lang/crystal/pull/7742), thanks @MakeNowJust) - Refactor old duplicated 'def contains_target'. ([#7739](https://github.com/crystal-lang/crystal/pull/7739), thanks @MakeNowJust) #### Formatter - Don't produce unnecessary newline before named args following heredoc. ([#7695](https://github.com/crystal-lang/crystal/pull/7695), thanks @MakeNowJust) - Fix formatting of multiline call arguments. ([#7745](https://github.com/crystal-lang/crystal/pull/7745), thanks @MakeNowJust) - Fix formatting of annotations with newlines and spaces. ([#7744](https://github.com/crystal-lang/crystal/pull/7744), thanks @MakeNowJust) - Refactor code to format &.[]. ([#7699](https://github.com/crystal-lang/crystal/pull/7699), thanks @MakeNowJust) ### Others - CI improvements and housekeeping. ([#7705](https://github.com/crystal-lang/crystal/pull/7705), [#7852](https://github.com/crystal-lang/crystal/pull/7852), thanks @bcardiff) - Move VERSION inside ./src. ([#7804](https://github.com/crystal-lang/crystal/pull/7804), thanks @bcardiff) ## 0.28.0 (2019-04-17) ### Language changes - **(breaking-change)** Enum declaration members can no longer be separated by a space, only by a newline, `;` or `,`, the latter being deprecated and reformatted to a newline. ([#7607](https://github.com/crystal-lang/crystal/pull/7607), [#7618](https://github.com/crystal-lang/crystal/pull/7618), thanks @asterite, and @j8r) - Add begin-less and end-less ranges: `array[5..]`. ([#7179](https://github.com/crystal-lang/crystal/pull/7179), thanks @asterite) - Add `offsetof(Type, @ivar)` expression. ([#7589](https://github.com/crystal-lang/crystal/pull/7589), thanks @malte-v) #### Macros - Add `Type#annotations` to list all annotations and not just the last of each kind. ([#7326](https://github.com/crystal-lang/crystal/pull/7326), thanks @Blacksmoke16) - Add `ArrayLiteral#sort_by` macro method. ([#3947](https://github.com/crystal-lang/crystal/pull/3947), thanks @jreinert) ### Standard library - **(breaking-change)** Allow creating `None` enum flag with `Enum.from_value`. ([#6516](https://github.com/crystal-lang/crystal/pull/6516), thanks @bew) - **(breaking-change)** Add deprecation message to `PartialComparable`. Its behaviour has been fully integrated into `Comparable`. ([#7664](https://github.com/crystal-lang/crystal/pull/7664), thanks @straight-shoota) - **(performance)** Optimize dwarf line numbers decoding. ([#7413](https://github.com/crystal-lang/crystal/pull/7413), thanks @asterite) - Fix `Signal::CHLD.reset` not clearing previous handler. ([#7409](https://github.com/crystal-lang/crystal/pull/7409), thanks @asterite) - Add lazy versions of `Object.getter?` and `Object.property?` macros. ([#7322](https://github.com/crystal-lang/crystal/pull/7322), thanks @Sija) - Allow returning other values than `-1`, `0` and `1` by `Comparable#<=>`. ([#7277](https://github.com/crystal-lang/crystal/pull/7277), thanks @r00ster91) - Add missing `require` statements to samples in the API docs. ([#7564](https://github.com/crystal-lang/crystal/pull/7564), thanks @Maroo-b) - Fix example codes in multiple places. ([#7569](https://github.com/crystal-lang/crystal/pull/7569), thanks @maiha) - Add documentation for `@[Flags]` and `@[Link]` annotations. ([#7665](https://github.com/crystal-lang/crystal/pull/7665), thanks @bcardiff) - Add documentation for `Bool`. ([#7651](https://github.com/crystal-lang/crystal/pull/7651), thanks @wontruefree) - Refactor to avoid usage of the thread-local `$errno` GLIBC_PRIVATE symbol. ([#7496](https://github.com/crystal-lang/crystal/pull/7496), thanks @felixvf) - Refactor to have similar signatures across the stdlib for `#to_s` and `#inspect`. ([#7528](https://github.com/crystal-lang/crystal/pull/7528), thanks @wontruefree) #### Numeric - **(breaking-change)** Add deprecation message to `Int#/`. It will return a `Float` in `0.29.0`. Use `Int#//` for integer division. ([#7639](https://github.com/crystal-lang/crystal/pull/7639), thanks @bcardiff) - Change `Number#inspect` to not show the type suffixes. ([#7525](https://github.com/crystal-lang/crystal/pull/7525), thanks @asterite) - Add `Int#leading_zeros_count` and `Int#trailing_zeros_count`. ([#7520](https://github.com/crystal-lang/crystal/pull/7520), thanks @Sija) - Add `Big*#//`, `BigInt#&`-ops and missing `#floor`, `#ceil`, `#trunc`. ([#7638](https://github.com/crystal-lang/crystal/pull/7638), thanks @bcardiff) - Improve `OverflowError` message. ([#7375](https://github.com/crystal-lang/crystal/pull/7375), thanks @r00ster91) #### Text - **(performance)** Optimize `String#compare` in case of ASCII only. ([#7352](https://github.com/crystal-lang/crystal/pull/7352), thanks @r00ster91) - Add methods for human-readable formatting of numbers: `Number#format`, `Number#humanize`, and `Int#humanize_bytes`. ([#6314](https://github.com/crystal-lang/crystal/pull/6314), thanks @straight-shoota) - Add `String#rchop?` and `String#lchop?`. ([#7328](https://github.com/crystal-lang/crystal/pull/7328), thanks @j8r) - Add `options` argument to `String#camelcase` and `String#underscore`. ([#7374](https://github.com/crystal-lang/crystal/pull/7374), thanks @r00ster91) - Add docs to `Unicode::CaseOptions`. ([#7513](https://github.com/crystal-lang/crystal/pull/7513), thanks @r00ster91) - Improve specs and docs for `String#each_line` and `IO#each_line`. ([#7419](https://github.com/crystal-lang/crystal/pull/7419), thanks @straight-shoota) #### Collections - **(breaking-change)** Let `Array#sort` only use `<=>`, and let `<=>` return `nil` for partial comparability. ([#6611](https://github.com/crystal-lang/crystal/pull/6611), thanks @asterite) - **(breaking-change)** Drop `Iterator#rewind`. Implement `#cycle` by storing elements in an array. ([#7440](https://github.com/crystal-lang/crystal/pull/7440), thanks @asterite) - **(performance)** Add `Enumerable#each_cons` support for `Deque` as a reuse buffer. ([#7233](https://github.com/crystal-lang/crystal/pull/7233), thanks @yxhuvud) - **(performance)** Change `Range#bsearch` `/ 2` to `>> 1` for faster performance. ([#7531](https://github.com/crystal-lang/crystal/pull/7531), thanks @Fryguy) - Fix `Slice#clone` for non-primitive types and deep copy. ([#7591](https://github.com/crystal-lang/crystal/pull/7591), thanks @straight-shoota) - Move `Indexable#zip` and `Indexable#zip?` to `Enumerable` and make it work with any number of `Indexable` or `Iterable` or `Iterator`. ([#7453](https://github.com/crystal-lang/crystal/pull/7453), thanks @asterite) - Add `Slice#[](Range)`. ([#7439](https://github.com/crystal-lang/crystal/pull/7439), thanks @asterite) - Add nillable range fetching `#[]?(Range)` to `Array` and `String`. ([#7338](https://github.com/crystal-lang/crystal/pull/7338), thanks @j8r) - Add `Set#add?`. ([#7495](https://github.com/crystal-lang/crystal/pull/7495), thanks @Sija) - Improve documentation of `Hash` regarding ordering of items. ([#7594](https://github.com/crystal-lang/crystal/pull/7594), thanks @straight-shoota) #### Serialization - **(breaking-change)** Change return type of `YAML#libyaml_version` to `SemanticVersion`. ([#7555](https://github.com/crystal-lang/crystal/pull/7555), thanks @asterite) - Fix support for libxml2 2.9.9. ([#7477](https://github.com/crystal-lang/crystal/pull/7477), thanks @asterite) - Fix support for libyaml 0.2.2. ([#7555](https://github.com/crystal-lang/crystal/pull/7555), thanks @asterite) - Add `BigDecimal.from_yaml`. ([#7398](https://github.com/crystal-lang/crystal/pull/7398), thanks @Sija) #### Time - **(breaking-change)** Rename `Time` constructors. Deprecate `Time.now` to encourage usage `Time.utc` or `Time.local` ([#5346](https://github.com/crystal-lang/crystal/pull/5346), [#7586](https://github.com/crystal-lang/crystal/pull/7586), thanks @straight-shoota) - **(breaking-change)** Rename `Time#add_span` to `Time#shift` for changing a time instance by calendar units and handle other units. ([#6598](https://github.com/crystal-lang/crystal/pull/6598), thanks @straight-shoota) - **(breaking-change)** Change `Time#date` to return a `Tuple` of `{year, month, day}`. Use `Time#at_beginning_of_day` if a `Time` instance is wanted. ([#5822](https://github.com/crystal-lang/crystal/pull/5822), thanks @straight-shoota) - Fix Windows monotonic time bug. ([#7377](https://github.com/crystal-lang/crystal/pull/7377), thanks @domgetter) - Refactor `Time` methods. ([#6581](https://github.com/crystal-lang/crystal/pull/6581), thanks @straight-shoota) #### Files - **(breaking-change)** Remove `IO#flush_on_newline` and only `sync` on `STDOUT`/`STDIN`/`STDERR` when they are TTY devices. ([#7470](https://github.com/crystal-lang/crystal/pull/7470), thanks @asterite) - Add `Path` type. ([#5635](https://github.com/crystal-lang/crystal/pull/5635), thanks @straight-shoota) #### Networking - **(breaking-change)** Move `HTTP::Multipart` to `MIME::Multipart`. ([#7085](https://github.com/crystal-lang/crystal/pull/7085), thanks @m1lt0n) - **(breaking-change)** Stop parsing JSON in OAuth2 errors. ([#7467](https://github.com/crystal-lang/crystal/pull/7467), thanks @asterite) - **(breaking-change)** Fix `RequestProcessor` connection reuse logic. ([#7055](https://github.com/crystal-lang/crystal/pull/7055), thanks @straight-shoota) - **(breaking-change)** Replace `HTTP.default_status_message_for(Int)` with `HTTP::Status.new(Int).description`. ([#7247](https://github.com/crystal-lang/crystal/pull/7247), thanks @dwightwatson) - **(breaking-change)** Fix issues in `URI` implementation. `URI#opaque` method is merged into `URI#path`, which no longer returns `Nil`. `#parse`/`#to_s` normalization and default port handling has changed. ([#6323](https://github.com/crystal-lang/crystal/pull/6323), thanks @straight-shoota) - Fix write buffering in OpenSSL sockets. ([#7460](https://github.com/crystal-lang/crystal/pull/7460), thanks @carlhoerberg) - Fix leaks in `HTTP::Server` `#bind_*` and specs. ([#7197](https://github.com/crystal-lang/crystal/pull/7197), thanks @straight-shoota) - Add `HTTP::Request#remote_address`. ([#7610](https://github.com/crystal-lang/crystal/pull/7610), thanks @asterite) - Add `HTTP::Status` and `Response#status`. ([#7247](https://github.com/crystal-lang/crystal/pull/7247), [#7682](https://github.com/crystal-lang/crystal/pull/7682), thanks @dwightwatson, and @bcardiff) - Add support for OAuth 2.0 resource owner password credentials grant type. ([#7424](https://github.com/crystal-lang/crystal/pull/7424), thanks @Blacksmoke16) - Add support for IIS date format in cookies. ([#7405](https://github.com/crystal-lang/crystal/pull/7405), thanks @Sija) - Allow calls to `IO::Syscall#wait_readable` and `IO::Syscall#wait_writable`. ([#7366](https://github.com/crystal-lang/crystal/pull/7366), thanks @stakach) - Fix spec of `HTTP::Client` to not write server response after timeout. ([#7402](https://github.com/crystal-lang/crystal/pull/7402), thanks @asterite) - Fix spec of `TCP::Server` for musl. ([#7484](https://github.com/crystal-lang/crystal/pull/7484), thanks @straight-shoota) #### Crypto - **(breaking-change)** Use `OpenSSL::Algorithm` instead of symbols for `digest`/`hexdigest`. Expose LibCrypt's `PKCS5_PBKDF2_HMAC`. ([#7264](https://github.com/crystal-lang/crystal/pull/7264), thanks @mniak) #### Concurrency - Add multi-threading ready GC when compiling with `-D preview_mt`. ([#7546](https://github.com/crystal-lang/crystal/pull/7546), thanks @bcardiff, @waj, and @ysbaddaden) - Ship patched bdw-gc for multi-threading support. ([#7622](https://github.com/crystal-lang/crystal/pull/7622), thanks @bcardiff, and @ysbaddaden) - Refactor to extract `Fiber::StackPool` from `Fiber`. ([#7417](https://github.com/crystal-lang/crystal/pull/7417), thanks @ysbaddaden) - Refactor `IO::Syscall` as `IO::Evented`. ([#7505](https://github.com/crystal-lang/crystal/pull/7505), thanks @ysbaddaden) #### System - Add command and args to `execvp` error message. ([#7511](https://github.com/crystal-lang/crystal/pull/7511), thanks @straight-shoota) - Refactor signals handling in a separate fiber. ([#7469](https://github.com/crystal-lang/crystal/pull/7469), thanks @asterite) #### Spec - Improve how running specs are cancelled upon `CTRL+C`. ([#7426](https://github.com/crystal-lang/crystal/pull/7426), thanks @asterite) - Allow `pending` and `it` to accept constants. ([#7646](https://github.com/crystal-lang/crystal/pull/7646), thanks @straight-shoota) ### Compiler - **(performance)** Avoid fork and spawn when `--threads=1`. ([#7397](https://github.com/crystal-lang/crystal/pull/7397), thanks @asterite) - Fix exception type thrown on missing require. ([#7386](https://github.com/crystal-lang/crystal/pull/7386), thanks @asterite) - Fix ICE when assigning a constant inside a multi-assign. ([#7468](https://github.com/crystal-lang/crystal/pull/7468), thanks @asterite) - Fix parsing and behaviour of `->foo.[]` and other operators . ([#7334](https://github.com/crystal-lang/crystal/pull/7334), thanks @asterite) - Fix parsing bug in `asm` with 3 colons and a variable. ([#7627](https://github.com/crystal-lang/crystal/pull/7627), thanks @r00ster91) - Opt-in detection of calls to `@[Deprecated]` methods. ([#7596](https://github.com/crystal-lang/crystal/pull/7596), [#7626](https://github.com/crystal-lang/crystal/pull/7626), [#7661](https://github.com/crystal-lang/crystal/pull/7661), thanks @bcardiff) - Add `CRYSTAL_LIBRARY_PATH` for lookup static libraries. ([#7562](https://github.com/crystal-lang/crystal/pull/7562), thanks @bcardiff) - Improve error messages by adding the scope (and `with ... yield` scope, if any) on undefined method error. ([#7384](https://github.com/crystal-lang/crystal/pull/7384), thanks @asterite) - Suggest `next` when trying to break from captured block . ([#7406](https://github.com/crystal-lang/crystal/pull/7406), thanks @r00ster91) - Add detection of linux environment in compiler config. ([#7479](https://github.com/crystal-lang/crystal/pull/7479), thanks @straight-shoota) - Pending leftovers to support `//` and `&`-ops in multiple places. ([#7628](https://github.com/crystal-lang/crystal/pull/7628), thanks @bcardiff) - Refactor `Crystal::Config.version` to use `read_file` macro. ([#7081](https://github.com/crystal-lang/crystal/pull/7081), thanks @Sija) - Rewrite macro spec without executing a shell command. ([#6962](https://github.com/crystal-lang/crystal/pull/6962), thanks @asterite) - Fix typo in internals. ([#7592](https://github.com/crystal-lang/crystal/pull/7592), thanks @toshokan) #### Language semantics - Fix issues with `as`, `as?` and unions and empty types. ([#7475](https://github.com/crystal-lang/crystal/pull/7475), thanks @asterite) - Fix method lookup when restrictions of instantiated and non-instantiated generic types are used. ([#7537](https://github.com/crystal-lang/crystal/pull/7537), thanks @bew) - Fix method lookup when free vars and explicit types are used. ([#7536](https://github.com/crystal-lang/crystal/pull/7536), [#7580](https://github.com/crystal-lang/crystal/pull/7580), thanks @bew) - When declaring a `protected initialize`, define a protected `new`. ([#7510](https://github.com/crystal-lang/crystal/pull/7510), thanks @asterite) - Fix named args type matching. ([#7529](https://github.com/crystal-lang/crystal/pull/7529), thanks @asterite) - Merge procs with the same arguments type and `Nil | T` return type to `Nil` return type. ([#7527](https://github.com/crystal-lang/crystal/pull/7527), thanks @asterite) - Fix passing recursive alias to proc. ([#7568](https://github.com/crystal-lang/crystal/pull/7568), thanks @asterite) ### Tools - Suggest the user to run the formatter in `travis.yml`. ([#7138](https://github.com/crystal-lang/crystal/pull/7138), thanks @KCErb) #### Formatter - Fix formatting of `1\n.as(Int32)`. ([#7347](https://github.com/crystal-lang/crystal/pull/7347), thanks @asterite) - Fix formatting of nested array elements. ([#7450](https://github.com/crystal-lang/crystal/pull/7450), thanks @MakeNowJust) - Fix formatting of comments and enums. ([#7605](https://github.com/crystal-lang/crystal/pull/7605), thanks @asterite) - Fix CLI handling of absolute paths input. ([#7560](https://github.com/crystal-lang/crystal/pull/7560), thanks @RX14) #### Doc generator - Don't include private constants. ([#7575](https://github.com/crystal-lang/crystal/pull/7575), thanks @r00ster91) - Include Crystal built-in constants. ([#7623](https://github.com/crystal-lang/crystal/pull/7623), thanks @bcardiff) - Add compile-time flag to docs generator. ([#6668](https://github.com/crystal-lang/crystal/pull/6668), [#7438](https://github.com/crystal-lang/crystal/pull/7438), thanks @straight-shoota) - Display deprecated label when `@[Deprecated]` is used. ([#7653](https://github.com/crystal-lang/crystal/pull/7653), thanks @bcardiff) #### Playground - Change the font-weight used for better readability. ([#7552](https://github.com/crystal-lang/crystal/pull/7552), thanks @Maroo-b) ### Others - CI improvements and housekeeping. ([#7359](https://github.com/crystal-lang/crystal/pull/7359), [#7381](https://github.com/crystal-lang/crystal/pull/7381), [#7388](https://github.com/crystal-lang/crystal/pull/7388), [#7387](https://github.com/crystal-lang/crystal/pull/7387), [#7390](https://github.com/crystal-lang/crystal/pull/7390), [#7622](https://github.com/crystal-lang/crystal/pull/7622), thanks @bcardiff) - Smoke test linux 64 bits package using docker image recent build. ([#7389](https://github.com/crystal-lang/crystal/pull/7389), thanks @bcardiff) - Mention git pre-commit hook in `CONTRIBUTING.md`. ([#7617](https://github.com/crystal-lang/crystal/pull/7617), thanks @straight-shoota) - Fix misspellings throughout the codebase. ([#7361](https://github.com/crystal-lang/crystal/pull/7361), thanks @Sija) - Use chars instead of strings throughout the codebase. ([#6237](https://github.com/crystal-lang/crystal/pull/6237), thanks @r00ster91) - Fix GC finalization warning in `Thread` specs. ([#7403](https://github.com/crystal-lang/crystal/pull/7403), thanks @asterite) - Remove generated docs from linux packages. ([#7519](https://github.com/crystal-lang/crystal/issues/7519), thanks @straight-shoota) ## 0.27.2 (2019-02-05) ### Standard library - Fixed integer overflow in main thread stack base detection. ([#7373](https://github.com/crystal-lang/crystal/pull/7373), thanks @ysbaddaden) #### Networking - Fixes TLS exception during shutdown. ([#7372](https://github.com/crystal-lang/crystal/pull/7372), thanks @bcardiff) - Fixed `HTTP::Client` support exception on missing Content-Type. ([#7371](https://github.com/crystal-lang/crystal/pull/7371), thanks @bew) ## 0.27.1 (2019-01-30) ### Language changes - Allow trailing commas inside tuple types. ([#7182](https://github.com/crystal-lang/crystal/pull/7182), thanks @asterite) ### Standard library - **(performance)** Optimize generating `UUID` from `String`. ([#7030](https://github.com/crystal-lang/crystal/pull/7030), thanks @jgaskins) - **(performance)** Improve `SemanticVersion` operations. ([#7234](https://github.com/crystal-lang/crystal/pull/7234), thanks @j8r) - Fixed markdown inline code parsing. ([#7090](https://github.com/crystal-lang/crystal/pull/7090), thanks @MakeNowJust) - Fixed inappropriate uses of `Time.now`. ([#7155](https://github.com/crystal-lang/crystal/pull/7155), thanks @straight-shoota) - Make `Nil#not_nil!` raise `NilAssertionError`. ([#7330](https://github.com/crystal-lang/crystal/pull/7330), thanks @r00ster91) - Add SemanticVersion to API docs. ([#7003](https://github.com/crystal-lang/crystal/pull/7003), thanks @Blacksmoke16) - Add docs to discourage the use of `Bool#to_unsafe` other than for C bindings. ([#7320](https://github.com/crystal-lang/crystal/pull/7320), thanks @oprypin) - Refactor `#to_s` to be independent of the `name` method. ([#7295](https://github.com/crystal-lang/crystal/pull/7295), thanks @asterite) #### Macros - Fixed docs of `ArrayLiteral#unshift`. ([#7127](https://github.com/crystal-lang/crystal/pull/7127), thanks @Blacksmoke16) - Fixed `Annotation#[]` to accept `String` and `Symbol` as keys. ([#7153](https://github.com/crystal-lang/crystal/pull/7153), thanks @MakeNowJust) - Fixed `NamedTupleLiteral#[]` to raise a compile error for invalid key type. ([#7158](https://github.com/crystal-lang/crystal/pull/7158), thanks @MakeNowJust) - Fixed `getter`/`property` macros to work properly with `Bool` types. ([#7313](https://github.com/crystal-lang/crystal/pull/7313), thanks @Sija) - Add `read_file` macro method. ([#6967](https://github.com/crystal-lang/crystal/pull/6967), [#7094](https://github.com/crystal-lang/crystal/pull/7094), thanks @Sija, @woodruffw) - Add `StringLiteral#count`. ([#7239](https://github.com/crystal-lang/crystal/pull/7239), thanks @Blacksmoke16) #### Numeric - Fixed scale issues when dividing `BigDecimal`. ([#7218](https://github.com/crystal-lang/crystal/pull/7218), thanks @Sija) - Allow underscores in the `String` passed to `Big*` constructors. ([#7107](https://github.com/crystal-lang/crystal/pull/7107), thanks @Sija) - Add conversion methods and docs to `Complex`. ([#5440](https://github.com/crystal-lang/crystal/pull/5440), thanks @Sija) - Add specs for `Int128`, `UInt128`. ([#7173](https://github.com/crystal-lang/crystal/pull/7173), thanks @bcardiff) - Add unsafe number ops `value.to_X!`/`T.new!`/`Int#&**`. ([#7226](https://github.com/crystal-lang/crystal/pull/7226), thanks @bcardiff) - Add overflow detection with preview opt-in. ([#7206](https://github.com/crystal-lang/crystal/pull/7206), thanks @bcardiff) #### Text - Fixed `ECR` location error reported. ([#7137](https://github.com/crystal-lang/crystal/pull/7137), thanks @MakeNowJust) - Add docs to ECR. ([#7121](https://github.com/crystal-lang/crystal/pull/7121), thanks @KCErb) - Refactor `String#to_i` to avoid future overflow. ([#7172](https://github.com/crystal-lang/crystal/pull/7172), thanks @bcardiff) #### Collections - Fixed docs example in `Hash#from`. ([#7210](https://github.com/crystal-lang/crystal/pull/7210), thanks @r00ster91) - Fixed docs links of `Enumerable#chunks` and `Iterator#chunk`. ([#6941](https://github.com/crystal-lang/crystal/pull/6941), thanks @r00ster91) - Remove implicit null skip from `Hash` to `JSON` serialization. ([#7053](https://github.com/crystal-lang/crystal/pull/7053), thanks @MakeNowJust) - Add `Iterator#slice_after`. ([#7146](https://github.com/crystal-lang/crystal/pull/7146), thanks @asterite) - Add `Iterator#slice_before`. ([#7152](https://github.com/crystal-lang/crystal/pull/7152), thanks @asterite) - Add `Iteratory#slice_when` and `Iterator#chunk_while`. ([#7159](https://github.com/crystal-lang/crystal/pull/7159), thanks @asterite) - Add `Enumerable#to_h(&block)`. ([#7150](https://github.com/crystal-lang/crystal/pull/7150), thanks @Sija) - Add `Enumerable#one?`. ([#7166](https://github.com/crystal-lang/crystal/pull/7166), thanks @asterite) - Add several `Enumerable`, `Iterator` and `Array` overloads that accept a pattern. ([#7174](https://github.com/crystal-lang/crystal/pull/7174), thanks @asterite) - Add docs to hash constructors. ([#6923](https://github.com/crystal-lang/crystal/pull/6923), thanks @KCErb) #### Serialization - Add conversion between JSON and YAML. ([#7232](https://github.com/crystal-lang/crystal/pull/7232), thanks @straight-shoota) - Standardize `#as_T`/`#as_T?` methods between `JSON::Any`/`YAML::Any`. ([#6556](https://github.com/crystal-lang/crystal/pull/6556), thanks @j8r) - Add `Set#from_yaml`. ([#6310](https://github.com/crystal-lang/crystal/pull/6310), thanks @kostya) #### Time - Fixed `Time::Span` initializer and `sleep` for big seconds. ([#7221](https://github.com/crystal-lang/crystal/pull/7221), thanks @asterite) - Fixed docs to show proper use of parse. ([#7035](https://github.com/crystal-lang/crystal/pull/7035), thanks @jwoertink) - Add missing `Float#weeks` method similar to `Int#weeks`. ([#7165](https://github.com/crystal-lang/crystal/pull/7165), thanks @vlazar) #### Files - Fix `mkstemps` support on aarch64. ([#7300](https://github.com/crystal-lang/crystal/pull/7300), thanks @silmanduin66) - Validate LibC error codes in specs involving Errno errors. ([#7087](https://github.com/crystal-lang/crystal/pull/7087), thanks @straight-shoota) - Add microsecond precision to `System::File.utime` (Unix). ([#7156](https://github.com/crystal-lang/crystal/pull/7156), thanks @straight-shoota) - Add missing tempfile cleanup in specs. ([#7250](https://github.com/crystal-lang/crystal/pull/7250), thanks @bcardiff) - Add docs for file open modes. ([#6664](https://github.com/crystal-lang/crystal/pull/6664), thanks @r00ster91) #### Networking - Fixed `HTTP::Client` edge case of exception during in TLS initialization. ([#7123](https://github.com/crystal-lang/crystal/pull/7123), thanks @asterite) - Fixed `OpenSSL::SSL::Error.new` to not raise `Errno`. ([#7068](https://github.com/crystal-lang/crystal/pull/7068), thanks @straight-shoota) - Fixed `URI` encoding in `StaticFileHandler::DirectoryListing`. ([#7072](https://github.com/crystal-lang/crystal/pull/7072), thanks @Sija) - Add MIME registry. ([#5765](https://github.com/crystal-lang/crystal/pull/5765), [#7079](https://github.com/crystal-lang/crystal/pull/7079), [#7080](https://github.com/crystal-lang/crystal/pull/7080), thanks @straight-shoota, @Sija) - Add `MIME::MediaType` for parsing mime media types. ([#7077](https://github.com/crystal-lang/crystal/pull/7077), thanks @straight-shoota) - Add support for 100-continue in `HTTP::Server::Response`. ([#6912](https://github.com/crystal-lang/crystal/pull/6912), thanks @jreinert) - Add support for creating sockets from raw file descriptors. ([#6894](https://github.com/crystal-lang/crystal/pull/6894), thanks @myfreeweb) - Add SNI support for OpenSSL. ([#7291](https://github.com/crystal-lang/crystal/pull/7291), thanks @bararchy) - Improve `HTTP::Server` docs. ([#7251](https://github.com/crystal-lang/crystal/pull/7251), thanks @straight-shoota) - Refactor `OpenSSL` specs to reduce chances of failing. ([#7202](https://github.com/crystal-lang/crystal/pull/7202), thanks @bcardiff) #### Crypto - Add `OpenSSL::Cipher#authenticated?` to see if the cipher supports aead. ([#7223](https://github.com/crystal-lang/crystal/pull/7223), thanks @danielwestendorf) #### System - Fixed inline ASM when compiling for ARM. ([#7041](https://github.com/crystal-lang/crystal/pull/7041), thanks @omarroth) - Implement `Crystal::System` for Win32. ([#6972](https://github.com/crystal-lang/crystal/pull/6972), thanks @markrjr) - Add `Errno#errno_message` getter. ([#6702](https://github.com/crystal-lang/crystal/pull/6702), thanks @r00ster91) #### Spec - Detect nesting `it` and `pending` at run-time. ([#7297](https://github.com/crystal-lang/crystal/pull/7297), thanks @MakeNowJust) ### Compiler - Fixed how `LLVM::Type.const_int` emit `Int128` literals. ([#7135](https://github.com/crystal-lang/crystal/pull/7135), thanks @bcardiff) - Fixed ICE related to named tuples. ([#7163](https://github.com/crystal-lang/crystal/pull/7163), thanks @asterite) - Fixed automatic casting for private top-level methods. ([#7310](https://github.com/crystal-lang/crystal/pull/7310), thanks @asterite) - Give proper error if defining initialize inside enum, allow `Enum.new`. ([#7266](https://github.com/crystal-lang/crystal/pull/7266), thanks @asterite) - Give proper error when trying to access instance variable of union type. ([#7194](https://github.com/crystal-lang/crystal/pull/7194), thanks @asterite) - Give proper error when trying to instantiate Module. ([#6735](https://github.com/crystal-lang/crystal/pull/6735), thanks @r00ster91) - Give proper error related to named arguments. ([#7288](https://github.com/crystal-lang/crystal/pull/7288), thanks @asterite) - Parse required comma between block args. ([#7343](https://github.com/crystal-lang/crystal/pull/7343), thanks @asterite) - Improve inference in recursion that involves blocks. ([#7161](https://github.com/crystal-lang/crystal/pull/7161), thanks @asterite) - Add locations to all expanded macro arguments. ([#7008](https://github.com/crystal-lang/crystal/pull/7008), thanks @MakeNowJust) - Turn a not compiler specific error while requiring into ICE. ([#7208](https://github.com/crystal-lang/crystal/pull/7208), thanks @MakeNowJust) - Remove old `nil?` error on pointer types. ([#7180](https://github.com/crystal-lang/crystal/pull/7180), thanks @asterite) - Improve too big tuple and named tuple error message. ([#7131](https://github.com/crystal-lang/crystal/pull/7131), thanks @r00ster91) - Workaround buggy offset debug info values. ([#7335](https://github.com/crystal-lang/crystal/pull/7335), thanks @bcardiff) - Refactor extract helper methods to emit `Float32`, `Float64` values. ([#7134](https://github.com/crystal-lang/crystal/pull/7134), thanks @bcardiff) - Refactor filename resolution logic out of `interpret_run`. ([#7051](https://github.com/crystal-lang/crystal/pull/7051), thanks @Sija) - Refactor internals regarding overflow. ([#7262](https://github.com/crystal-lang/crystal/pull/7262), thanks @bcardiff) - Refactor `Crystal::Codegen::Target` and consolidate triple handling. ([#7282](https://github.com/crystal-lang/crystal/pull/7282), [#7317](https://github.com/crystal-lang/crystal/pull/7317), thanks @RX14, @bcardiff) ### Tools - Update README template. ([#7118](https://github.com/crystal-lang/crystal/pull/7118), thanks @mamantoha) - Capitalise Crystal in CLI output. ([#7224](https://github.com/crystal-lang/crystal/pull/7224), thanks @dwightwatson) #### Formatter - Fixed formatting of multiline literal elements. ([#7048](https://github.com/crystal-lang/crystal/pull/7048), thanks @MakeNowJust) - Fixed formatting of heredoc with interpolations. ([#7184](https://github.com/crystal-lang/crystal/pull/7184), thanks @MakeNowJust) - Fixed prevent conflict between nested tuple types and macro expressions. ([#7097](https://github.com/crystal-lang/crystal/pull/7097), thanks @MakeNowJust) - Fixed format when `typeof` appears inside generic type. ([#7176](https://github.com/crystal-lang/crystal/pull/7176), thanks @asterite) - Fixed format of newline after `&.foo` in call. ([#7240](https://github.com/crystal-lang/crystal/pull/7240), thanks @MakeNowJust) - Honor same behaviour for single or multiple file arguments. ([#7144](https://github.com/crystal-lang/crystal/pull/7144), thanks @straight-shoota) - Refactor remove quotes from overflow symbols in formatter spec. ([#6968](https://github.com/crystal-lang/crystal/pull/6968), thanks @r00ster91) - Major rework of `crystal tool format` command. ([#7257](https://github.com/crystal-lang/crystal/pull/7257), thanks @MakeNowJust) #### Doc generator - **(security)** Prevent XSS via args. ([#7056](https://github.com/crystal-lang/crystal/pull/7056), thanks @MakeNowJust) - Fixed generation of toplevel. ([#7063](https://github.com/crystal-lang/crystal/pull/7063), thanks @MakeNowJust) - Fixed display of double splat and block arg. ([#7029](https://github.com/crystal-lang/crystal/pull/7029), [#7031](https://github.com/crystal-lang/crystal/pull/7031), thanks @MakeNowJust) - Fixed keep trailing spaces in macros. ([#7099](https://github.com/crystal-lang/crystal/pull/7099), thanks @MakeNowJust) - Fixed avoid showing subtypes of aliased type. ([#7124](https://github.com/crystal-lang/crystal/pull/7124), thanks @asterite) - Fixed style of methods when hovering. ([#7022](https://github.com/crystal-lang/crystal/pull/7022), thanks @r00ster91) - Fixed duplicate `source_link` field. ([#7033](https://github.com/crystal-lang/crystal/pull/7033), thanks @bcardiff) - Fixed missing keywords in `Doc::Highlighter`. ([#7054](https://github.com/crystal-lang/crystal/pull/7054), thanks @MakeNowJust) - Add `--format` option to docs command. ([#6982](https://github.com/crystal-lang/crystal/pull/6982), thanks @mniak) ### Others - CI improvements and housekeeping. ([#7018](https://github.com/crystal-lang/crystal/pull/7018), [#7043](https://github.com/crystal-lang/crystal/pull/7043), [#7133](https://github.com/crystal-lang/crystal/pull/7133), [#7139](https://github.com/crystal-lang/crystal/pull/7139), [#7230](https://github.com/crystal-lang/crystal/pull/7230), [#7227](https://github.com/crystal-lang/crystal/pull/7227), [#7263](https://github.com/crystal-lang/crystal/pull/7263), thanks @bcardiff) - CI split formatting check. ([#7228](https://github.com/crystal-lang/crystal/pull/7228), thanks @bcardiff) - Depend on standard variable to let the user define the build date. ([#7186](https://github.com/crystal-lang/crystal/pull/7186), thanks @eli-schwartz) - Reorganize community section in README, add forum. ([#7235](https://github.com/crystal-lang/crystal/pull/7235), thanks @straight-shoota) - Fixed docs grammar and typos. ([#7034](https://github.com/crystal-lang/crystal/pull/7034), [#7242](https://github.com/crystal-lang/crystal/pull/7242), [#7331](https://github.com/crystal-lang/crystal/pull/7331), thanks @r00ster91, @girng) - Improve samples. ([#6454](https://github.com/crystal-lang/crystal/pull/6454), thanks @r00ster91) - Fixed 0.27.0 CHANGELOG. ([#7024](https://github.com/crystal-lang/crystal/pull/7024), thanks @arcage) - Update ISSUE_TEMPLATE to include forum. ([#7301](https://github.com/crystal-lang/crystal/pull/7301), thanks @straight-shoota) - Update LICENSE's copyright year. ([#7246](https://github.com/crystal-lang/crystal/pull/7246), thanks @matiasgarciaisaia) ## 0.27.0 (2018-11-01) ### Language changes - **(breaking-change)** Disallow comma after newline in argument list. ([#6514](https://github.com/crystal-lang/crystal/pull/6514), thanks @asterite) #### Macros - Add `Generic#resolve` and `Generic#resolve?` macro methods. ([#6617](https://github.com/crystal-lang/crystal/pull/6617), thanks @asterite) ### Standard library - Fixed `v1`, `v2`, `v3`, `v4`, `v5` methods of `UUID`. ([#6952](https://github.com/crystal-lang/crystal/pull/6952), thanks @r00ster91) - Fixed multiple docs typos and phrasing in multiple places. ([#6778](https://github.com/crystal-lang/crystal/pull/6778), [#6963](https://github.com/crystal-lang/crystal/pull/6963), thanks @r00ster91) - Fixes `Pointer`/`UInt` subtraction. ([#6994](https://github.com/crystal-lang/crystal/pull/6994), thanks @damaxwell) - Add stack overflow detection. ([#6928](https://github.com/crystal-lang/crystal/pull/6928), [#6995](https://github.com/crystal-lang/crystal/pull/6995), thanks @damaxwell) - Add caller file and line to `Nil#not_nil!`. ([#6712](https://github.com/crystal-lang/crystal/pull/6712), thanks @yeeunmariakim) - Restrict `Enum#parse`/`Enum#parse?` to `String` arguments. ([#6654](https://github.com/crystal-lang/crystal/pull/6654), thanks @vladfaust) - Refactor and unify printing exceptions from within fibers. ([#6594](https://github.com/crystal-lang/crystal/pull/6594), thanks @Sija) - Improve docs on properties generated by `property?`. ([#6682](https://github.com/crystal-lang/crystal/pull/6682), thanks @epergo) - Add docs to top level namespace constants. ([#6971](https://github.com/crystal-lang/crystal/pull/6971), thanks @r00ster91) #### Macros - Fix typos in `StringLiteral#gsub` and `#tr` errors. ([#6925](https://github.com/crystal-lang/crystal/pull/6925), thanks @r00ster91) #### Numeric - **(breaking-change)** Disallow `rand` with zero value. ([#6686](https://github.com/crystal-lang/crystal/pull/6686), thanks @oprypin) - **(breaking-change)** Let `==` and `!=` compare the values instead of bits when dealing with signed vs unsigned integers. ([#6689](https://github.com/crystal-lang/crystal/pull/6689), thanks @asterite) - Fixed `Int#downto` with unsigned int. ([#6678](https://github.com/crystal-lang/crystal/pull/6678), thanks @gmarcais) - Add wrapping arithmetics operators `&+` `&-` `&*`. ([#6890](https://github.com/crystal-lang/crystal/pull/6890), thanks @bcardiff) - Add floor divisions operator `Int#//` and `Float#//`. ([#6891](https://github.com/crystal-lang/crystal/pull/6891), thanks @bcardiff) - Add random support for `BigInt`. ([#6687](https://github.com/crystal-lang/crystal/pull/6687), thanks @oprypin) - Add docs related to `Float::Printer::*`. ([#5438](https://github.com/crystal-lang/crystal/pull/5438), thanks @Sija) #### Text - Add `String::Builder#chomp!` returns self. ([#6583](https://github.com/crystal-lang/crystal/pull/6583), thanks @Sija) - Add `:default` to colorize and document `ColorRGB`, `Color256`. ([#6427](https://github.com/crystal-lang/crystal/pull/6427), thanks @r00ster91) - Add `String::Formatter` support for `c` flag and improve docs. ([#6758](https://github.com/crystal-lang/crystal/pull/6758), thanks @r00ster91) #### Collections - **(breaking-change)** Replace `Indexable#at` with `#fetch`. Remove `Hash#fetch(key)` as alias of `Hash#[]`. ([#6296](https://github.com/crystal-lang/crystal/pull/6296), thanks @AlexWayfer) - Add `Hash/Indexable#dig/dig?`. ([#6719](https://github.com/crystal-lang/crystal/pull/6719), thanks @Sija) - Add `Iterator.chain` to chain array of iterators. ([#6570](https://github.com/crystal-lang/crystal/pull/6570), thanks @xqyww123) - Add `NamedTuple#to_h` over empty tuples. ([#6628](https://github.com/crystal-lang/crystal/pull/6628), thanks @icyleaf) - Optimize `Indexable#join` when all elements are strings. ([#6635](https://github.com/crystal-lang/crystal/pull/6635), thanks @asterite) - Optimize `Array#skip`. ([#6946](https://github.com/crystal-lang/crystal/pull/6946), thanks @asterite) #### Serialization - Fixed `YAML::Schema::FailSafe.parse` and `parse_all`. ([#6790](https://github.com/crystal-lang/crystal/pull/6790), thanks @r00ster91) - Fixed order of `xmlns` and prefix in `XML::Builder#namespace`. ([#6743](https://github.com/crystal-lang/crystal/pull/6743), thanks @yeeunmariakim) - Fixed `CSV.build` quoting of `Char` and `Symbol`. ([#6904](https://github.com/crystal-lang/crystal/pull/6904), thanks @maiha) - Fixed docs for `JSON::Serializable`. ([#6950](https://github.com/crystal-lang/crystal/pull/6950), thanks @Heaven31415) - Add `XML::Attributes#delete`. ([#6910](https://github.com/crystal-lang/crystal/pull/6910), thanks @joenas) - Add ability to quote values always in `CSV.build`. ([#6723](https://github.com/crystal-lang/crystal/pull/6723), thanks @maiha) - Refactor how empty properties are handled in `JSON::Serializable` and `YAML::Serializable`. ([#6539](https://github.com/crystal-lang/crystal/pull/6539), thanks @r00ster91) #### Time - **(breaking-change)** Rename `Time#epoch` to `Time#to_unix`. Also `#epoch_ms` to `#to_unix_ms`, and `#epoch_f` to `#to_unix_f`. ([#6662](https://github.com/crystal-lang/crystal/pull/6662), thanks @straight-shoota) - Fixed spec for `Time::Location.load_local` with `TZ=nil`. ([#6740](https://github.com/crystal-lang/crystal/pull/6740), thanks @straight-shoota) - Add support for ISO calendar week to `Time`. ([#6681](https://github.com/crystal-lang/crystal/pull/6681), thanks @straight-shoota) - Add `Time::Format` support for `%G`, `%g`, `%V`. ([#6681](https://github.com/crystal-lang/crystal/pull/6681), thanks @straight-shoota) - Add `Time::Location` loader support for Windows. ([#6363](https://github.com/crystal-lang/crystal/pull/6363), thanks @straight-shoota) - Add `Time#to_local_in` to change time zone while keeping wall clock. ([#6572](https://github.com/crystal-lang/crystal/pull/6572), thanks @straight-shoota) - Add `Time::UNIX_EPOCH` and drop private `UNIX_SECONDS` constant. ([#6908](https://github.com/crystal-lang/crystal/pull/6908), thanks @j8r) - Change `Time::DayOfWeek` to ISO ordinal numbering based on `Monday = 1`. ([#6555](https://github.com/crystal-lang/crystal/pull/6555), thanks @straight-shoota) - Refactor time specs. ([#6574](https://github.com/crystal-lang/crystal/pull/6574), thanks @straight-shoota) - Add docs for singular method aliases, add `Int#microsecond` alias. ([#6297](https://github.com/crystal-lang/crystal/pull/6297), thanks @Sija) #### Files - **(breaking-change)** Remove `Tempfile`. Use `File.tempfile` or `File.tempname`. ([#6485](https://github.com/crystal-lang/crystal/pull/6485), thanks @straight-shoota) - Fixed missing closed status check of FDs when creating a subprocess. ([#6641](https://github.com/crystal-lang/crystal/pull/6641), thanks @Timbus) - Fixed `ChecksumReader.write` error message. ([#6889](https://github.com/crystal-lang/crystal/pull/6889), thanks @r00ster91) - Add `File#delete`, `Dir#tempdir` and improve `File` docs. ([#6485](https://github.com/crystal-lang/crystal/pull/6485), thanks @straight-shoota) - Add `File#fsync` to flush all data written into the file to the disk device. ([#6793](https://github.com/crystal-lang/crystal/pull/6793), thanks @carlhoerberg) - Add `DEVNULL` to docs. ([#6642](https://github.com/crystal-lang/crystal/pull/6642), thanks @r00ster91) - Improve checks for FreeBSD version due to breaking API changes. ([#6629](https://github.com/crystal-lang/crystal/pull/6629), thanks @myfreeweb) - Improve performance of `Zlib::Reader`, `Gzip::Reader` and `Flate::Reader` by including `IO::Buffered`. ([#6916](https://github.com/crystal-lang/crystal/pull/6916), thanks @asterite) - Refactor `Crystal::System::FileDescriptor` to use `@fd` ivar directly. ([#6703](https://github.com/crystal-lang/crystal/pull/6703), thanks @straight-shoota) - Refactor `{Zlib,Gzip,Flate}::Reader#unbuffered_rewind` to use `check_open`. ([#6958](https://github.com/crystal-lang/crystal/pull/6958), thanks @Sija) #### Networking - **(breaking-change)** Remove deprecated alias `HTTP::Server#bind_ssl`. Use `HTTP::Server#bind_tls`. ([#6699](https://github.com/crystal-lang/crystal/pull/6699), thanks @straight-shoota) - Add `Socket::Address#pretty_print` and `#inspect`. ([#6704](https://github.com/crystal-lang/crystal/pull/6704), thanks @straight-shoota) - Add `Socket::IPAddress` loopback, unspecified and broadcast methods/constants. ([#6710](https://github.com/crystal-lang/crystal/pull/6710), thanks @straight-shoota) - Fixed `Socket#reuse_port?` if `SO_REUSEPORT` is not supported. ([#6706](https://github.com/crystal-lang/crystal/pull/6706), thanks @straight-shoota) - Fixed `TCPServer` handling of `reuse_port`. ([#6940](https://github.com/crystal-lang/crystal/pull/6940), thanks @RX14) - Add docs to demonstrate parameters for `HTTP::Client`. ([#5145](https://github.com/crystal-lang/crystal/pull/5145), thanks @HCLarsen) - Add docs examples to `Socket::Server#accept`. ([#6705](https://github.com/crystal-lang/crystal/pull/6705), thanks @straight-shoota) - Refactor `socket_spec.cr` into separate files. ([#6700](https://github.com/crystal-lang/crystal/pull/6700), thanks @straight-shoota) - Refactor specs of `HTTP::Client` to remove inheritance for test server. ([#6909](https://github.com/crystal-lang/crystal/pull/6909), thanks @straight-shoota) - Improve specs for `HTTP::Server#close`. ([#5958](https://github.com/crystal-lang/crystal/pull/5958), thanks @straight-shoota) - Improve specs for socket. ([#6711](https://github.com/crystal-lang/crystal/pull/6711), thanks @straight-shoota) #### Crypto - Fixed OpenSSL bindings to work with LibreSSL. ([#6917](https://github.com/crystal-lang/crystal/pull/6917), thanks @LVMBDV) - Add support for OpenSSL 1.1.1. ([#6738](https://github.com/crystal-lang/crystal/pull/6738), thanks @ysbaddaden) #### Concurrency - Improve POSIX threads integration regarding locking, error and resource management. ([#6944](https://github.com/crystal-lang/crystal/pull/6944), thanks @ysbaddaden) - Remove unintended public methods from `Channel`. ([#6714](https://github.com/crystal-lang/crystal/pull/6714), thanks @asterite) - Refactor `Fiber`/`Scheduler` to isolate responsibilities. ([#6897](https://github.com/crystal-lang/crystal/pull/6897), thanks @ysbaddaden) - Refactor specs that relied on `Fiber.yield` behavior. ([#6953](https://github.com/crystal-lang/crystal/pull/6953), thanks @ysbaddaden) #### System - Fixed fork and signal child handlers. ([#6426](https://github.com/crystal-lang/crystal/pull/6426), thanks @ysbaddaden) - Use blocking `IO` on a TTY if it can't be reopened. ([#6660](https://github.com/crystal-lang/crystal/pull/6660), thanks @Timbus) - Refactor `Process` in preparation for Windows support. ([#6744](https://github.com/crystal-lang/crystal/pull/6744), thanks @RX14) #### Spec - Allow `pending` to be used without blocks. ([#6732](https://github.com/crystal-lang/crystal/pull/6732), thanks @tswicegood) - Add `be_empty` expectation. ([#6614](https://github.com/crystal-lang/crystal/pull/6614), thanks @mamantoha) - Add specs for expectation methods. ([#6512](https://github.com/crystal-lang/crystal/pull/6512), thanks @rodrigopinto) ### Compiler - Fixed don't "ambiguous match" if there's an exact match. ([#6618](https://github.com/crystal-lang/crystal/pull/6618), thanks @asterite) - Fixed allow annotations inside enums. ([#6713](https://github.com/crystal-lang/crystal/pull/6713), thanks @asterite) - Fixed `super` inside macros will honor arguments. ([#6638](https://github.com/crystal-lang/crystal/pull/6638), thanks @asterite) - Fixed guessed ivar type from splat arguments. ([#6648](https://github.com/crystal-lang/crystal/pull/6648), thanks @MakeNowJust) - Fixed `ASTNode#to_s` of non-unary operator call without argument. ([#6538](https://github.com/crystal-lang/crystal/pull/6538), thanks @MakeNowJust) - Fixed `ASTNode#to_s` for multiline macro expression. ([#6666](https://github.com/crystal-lang/crystal/pull/6666), thanks @MakeNowJust) - Fixed `ASTNode#to_s` for `{% verbatim do %} ... {% end %}`. ([#6665](https://github.com/crystal-lang/crystal/pull/6665), thanks @MakeNowJust) - Fixed empty case statement normalization. ([#6915](https://github.com/crystal-lang/crystal/pull/6915), thanks @straight-shoota) - Fixed codegen of tuple elements with unreachable elements. ([#6659](https://github.com/crystal-lang/crystal/pull/6659), thanks @MakeNowJust) - Fixed parsing of `//` corner cases. ([#6927](https://github.com/crystal-lang/crystal/pull/6927), thanks @bcardiff) - Fixed recursive block expansion check for non `ProcNotation` restriction. ([#6932](https://github.com/crystal-lang/crystal/pull/6932), thanks @MakeNowJust) - Fixed corner case of expressions not typed on main phase but typed on cleanup phase. ([#6720](https://github.com/crystal-lang/crystal/pull/6720), thanks @MakeNowJust) - Improve error traces regarding `return`, `next` and `break`. ([#6633](https://github.com/crystal-lang/crystal/pull/6633), thanks @asterite) - Add resolve generics typenodes in macros. ([#6617](https://github.com/crystal-lang/crystal/pull/6617), thanks @asterite) - Add support for multiple output values in inline asm. ([#6680](https://github.com/crystal-lang/crystal/pull/6680), thanks @RX14) - Improve parsing of `asm` operands. ([#6688](https://github.com/crystal-lang/crystal/pull/6688), thanks @RX14) - Refactor rescue block codegen for Windows. ([#6649](https://github.com/crystal-lang/crystal/pull/6649), thanks @RX14) ### Tools - Improve installation section in README template. ([#6914](https://github.com/crystal-lang/crystal/pull/6914), [#6942](https://github.com/crystal-lang/crystal/pull/6942), thanks @r00ster91) - Improve contributors section in README template. ([#7005](https://github.com/crystal-lang/crystal/pull/7005), thanks @r00ster91) #### Formatter - Fixed formatting of `{% verbatim do %} ... {% end %}` outside macro. ([#6667](https://github.com/crystal-lang/crystal/pull/6667), thanks @MakeNowJust) - Fixed formatting of `//` corner cases. ([#6927](https://github.com/crystal-lang/crystal/pull/6927), thanks @bcardiff) - Improve formatting of `asm` operands. ([#6688](https://github.com/crystal-lang/crystal/pull/6688), thanks @RX14) #### Doc generator - Add support for comments after `:nodoc:` marker. ([#6627](https://github.com/crystal-lang/crystal/pull/6627), thanks @Sija) - Fixed browser performance issue with blur filter. ([#6764](https://github.com/crystal-lang/crystal/pull/6764), thanks @girng) - Accessibility improvement in search field. ([#6926](https://github.com/crystal-lang/crystal/pull/6926), thanks @jodylecompte) ### Others - CI improvements and housekeeping. ([#6658](https://github.com/crystal-lang/crystal/pull/6658), [#6739](https://github.com/crystal-lang/crystal/pull/6739), [#6930](https://github.com/crystal-lang/crystal/pull/6930), thanks @bcardiff, @RX14) - Add `VERSION` file and support for specifying the build commit. ([#6966](https://github.com/crystal-lang/crystal/pull/6966), thanks @bcardiff) - Add support for specifying the build date. ([#6788](https://github.com/crystal-lang/crystal/pull/6788), thanks @peterhoeg) - Update Contributing section in `README.md`. ([#6911](https://github.com/crystal-lang/crystal/pull/6911), thanks @r00ster91) ## 0.26.1 (2018-08-27) ### Language changes - **(breaking-change)** Make `self` to be eager evaluated when including modules. ([#6557](https://github.com/crystal-lang/crystal/pull/6557), thanks @bcardiff) #### Macros - Add `accepts_block?` macro method to `Def`. ([#6604](https://github.com/crystal-lang/crystal/pull/6604), thanks @willhbr) ### Standard library #### Macros - Fixed `Object#def_hash` can receive symbols. ([#6531](https://github.com/crystal-lang/crystal/pull/6531), thanks @Sija) #### Collections - Add `Hash#transform_keys` and `Hash#transform_values`. ([#4385](https://github.com/crystal-lang/crystal/pull/4385), thanks @deepj) #### Serialization - Fixed `JSON::Serializable` and `YAML::Serializable` clashing with custom initializers. ([#6458](https://github.com/crystal-lang/crystal/pull/6458), thanks @kostya) #### Time - Fixed docs for `Time::Format`. ([#6578](https://github.com/crystal-lang/crystal/pull/6578), thanks @straight-shoota) #### Files - Fixed zlib handling of buffer error. ([#6610](https://github.com/crystal-lang/crystal/pull/6610), thanks @asterite) #### Networking - **(deprecate)** `HTTP::Server#bind_ssl` in favor of `HTTP::Server#bind_tls`. ([#6551](https://github.com/crystal-lang/crystal/pull/6551), thanks @bcardiff) - Add tls scheme to `HTTP::Server#bind`. ([#6533](https://github.com/crystal-lang/crystal/pull/6533), thanks @straight-shoota) - Fixed `HTTP::Server` crash with self-signed certificate. ([#6590](https://github.com/crystal-lang/crystal/pull/6590), thanks @bcardiff) - Refactor `HTTP::Server` specs to use free ports. ([#6530](https://github.com/crystal-lang/crystal/pull/6530), thanks @straight-shoota) #### System - Improve `STDIN`/`STDOUT`/`STDERR` handling to avoid breaking other programs. ([#6518](https://github.com/crystal-lang/crystal/pull/6518), thanks @Timbus) #### Spec - Fixed `DotFormatter` to flush after every spec. ([#6562](https://github.com/crystal-lang/crystal/pull/6562), thanks @asterite) - Add support for Windows. ([#6497](https://github.com/crystal-lang/crystal/pull/6497), thanks @RX14) ### Compiler - Fixed evaluate yield expressions in macros. ([#6587](https://github.com/crystal-lang/crystal/pull/6587), thanks @asterite) - Fixed presence check of named argument via external name. ([#6560](https://github.com/crystal-lang/crystal/pull/6560), thanks @asterite) - Fixed parser error on `break when`. ([#6509](https://github.com/crystal-lang/crystal/pull/6509), thanks @asterite) - Fixed `~` methods are now able to be called as `foo.~`. ([#6541](https://github.com/crystal-lang/crystal/pull/6541), thanks @MakeNowJust) - Fixed parsing newline after macro control expression. ([#6607](https://github.com/crystal-lang/crystal/pull/6607), thanks @asterite) - Refactor use enum instead of hardcoded string values for emit kinds. ([#6515](https://github.com/crystal-lang/crystal/pull/6515), thanks @bew) ### Tools #### Formatter - Fixed formatting of newline before `&.method` in call. ([#6535](https://github.com/crystal-lang/crystal/pull/6535), thanks @MakeNowJust) - Fixed formatting of empty heredoc. ([#6567](https://github.com/crystal-lang/crystal/pull/6567), thanks @MakeNowJust) - Fixed formatting of string literal in interpolation. ([#6568](https://github.com/crystal-lang/crystal/pull/6568), thanks @MakeNowJust) - Fixed formatting of comments in case when. ([#6595](https://github.com/crystal-lang/crystal/pull/6595), thanks @asterite) #### Doc generator - Add Menlo font family and fix ordering. ([#6602](https://github.com/crystal-lang/crystal/pull/6602), thanks @slice) #### Playground - Fixed internal link. ([#6596](https://github.com/crystal-lang/crystal/pull/6596), thanks @omarroth) ### Others - CI improvements and housekeeping. ([#6550](https://github.com/crystal-lang/crystal/pull/6550), [#6612](https://github.com/crystal-lang/crystal/pull/6612), thanks @bcardiff) - Add `pkg-config` as Linux package dependency. ([distribution-scripts#16](https://github.com/crystal-lang/distribution-scripts/pull/16), thanks @bcardiff) ## 0.26.0 (2018-08-09) ### Language changes - **(breaking-change)** Revert do not collapse unions for sibling types. ([#6351](https://github.com/crystal-lang/crystal/pull/6351), thanks @asterite) - **(breaking-change)** Constant lookup context in macro is now lexical. ([#5354](https://github.com/crystal-lang/crystal/pull/5354), thanks @MakeNowJust) - **(breaking-change)** Evaluate instance var initializers at the metaclass level (ie: disallow using `self`). ([#6414](https://github.com/crystal-lang/crystal/pull/6414), thanks @asterite) - **(breaking-change)** Add `//` operator parsing. NB: No behaviour is assigned to this operator yet. ([#6470](https://github.com/crystal-lang/crystal/pull/6470), thanks @bcardiff) - Add `&+` `&-` `&*` `&**` operators parsing. NB: No behaviour is assigned to these operators yet. ([#6329](https://github.com/crystal-lang/crystal/pull/6329), thanks @bcardiff) - Add support for empty `case` without `when`. ([#6367](https://github.com/crystal-lang/crystal/pull/6367), thanks @straight-shoota) #### Macros - Add `pp!` and `p!` macro methods. ([#6374](https://github.com/crystal-lang/crystal/pull/6374), [#6476](https://github.com/crystal-lang/crystal/pull/6476), thanks @straight-shoota) ### Standard library - Fix docs for `Pointer`. ([#6494](https://github.com/crystal-lang/crystal/pull/6494), thanks @fxn) - Fix docs of `UUID` enums. ([#6496](https://github.com/crystal-lang/crystal/pull/6496), thanks @r00ster91) #### Numeric - Fixed `Random#rand(Range(Float, Float))` to return `Float`. ([#6445](https://github.com/crystal-lang/crystal/pull/6445), thanks @straight-shoota) - Add docs of big module overloads. ([#6336](https://github.com/crystal-lang/crystal/pull/6336), thanks @laginha87) #### Text - **(breaking-change)** `String#from_utf16(pointer : Pointer(UInt16))` returns now `{String, Pointer(UInt16)}`. ([#6333](https://github.com/crystal-lang/crystal/pull/6333), thanks @straight-shoota) - Add support for unicode 11.0.0. ([#6505](https://github.com/crystal-lang/crystal/pull/6505), thanks @asterite) - Add an optional argument to `String#check_no_null_byte` to customize error message. ([#6333](https://github.com/crystal-lang/crystal/pull/6333), thanks @straight-shoota) - Add `ECR.render` for rendering directly as `String`. ([#6371](https://github.com/crystal-lang/crystal/pull/6371), thanks @straight-shoota) - Fix docs for `Char` ([#6487](https://github.com/crystal-lang/crystal/pull/6487), thanks @r00ster91) #### Collections - Add docs for `StaticArray`. ([#6404](https://github.com/crystal-lang/crystal/pull/6404), [#6488](https://github.com/crystal-lang/crystal/pull/6488), thanks @straight-shoota, @r00ster91, @hinrik) - Refactor `Array#concat`. ([#6493](https://github.com/crystal-lang/crystal/pull/6493), thanks @fxn) #### Serialization - **(breaking-change)** Add a maximum nesting level to prevent stack overflow on `YAML::Builder` and `JSON::Builder`. ([#6322](https://github.com/crystal-lang/crystal/pull/6322), thanks @asterite) - Fixed compatibility for libyaml 0.2.1 regarding document end marker `...`. ([#6287](https://github.com/crystal-lang/crystal/pull/6287), thanks @straight-shoota) - Add methods and options for pull parsing or hybrid parsing to `XML::Reader`. ([#5740](https://github.com/crystal-lang/crystal/pull/5740), [#6332](https://github.com/crystal-lang/crystal/pull/6332), thanks @felixbuenemann) - Fixed docs for `JSON::Any`, `JSON::Serialization` and `YAML::Serialization`. ([#6460](https://github.com/crystal-lang/crystal/pull/6460), [#6491](https://github.com/crystal-lang/crystal/pull/6491), thanks @delef, @bmulvihill) #### Time - **(breaking-change)** Make location a required argument for `Time.parse`. ([#6369](https://github.com/crystal-lang/crystal/pull/6369), thanks @straight-shoota) - Add `Time.parse!`, `Time.parse_utc`, `Time.parse_local`. ([#6369](https://github.com/crystal-lang/crystal/pull/6369), thanks @straight-shoota) - Fix docs comment missing ([#6387](https://github.com/crystal-lang/crystal/pull/6387), thanks @faustinoaq) #### Files - **(breaking-change)** Remove `File.each_line` method that returns an iterator. Use `IO#each_line`. ([#6301](https://github.com/crystal-lang/crystal/pull/6301), thanks @asterite) - Fixed `File.join` when path separator is a component argument. ([#6328](https://github.com/crystal-lang/crystal/pull/6328), thanks @icyleaf) - Fixed `Dir.glob` can now list broken symlinks. ([#6466](https://github.com/crystal-lang/crystal/pull/6466), thanks @straight-shoota) - Add `File` and `Dir` support for Windows. ([#5623](https://github.com/crystal-lang/crystal/pull/5623), thanks @RX14) #### Networking - **(breaking-change)** Drop `HTTP::Server#tls` in favor of `HTTP::Server#bind_ssl`. ([#5960](https://github.com/crystal-lang/crystal/pull/5960), thanks @straight-shoota) - **(breaking-change)** Rename alias `HTTP::Handler::Proc` to `HTTP::Handler::HandlerProc`. ([#6453](https://github.com/crystal-lang/crystal/pull/6453), thanks @jwoertink) - Fixed `Socket#accept?` base implementation. ([#6277](https://github.com/crystal-lang/crystal/pull/6277), thanks @ysbaddaden) - Fixed performance issue due to unbuffered `IO` read. `IO#sync` only affect writes, introduce `IO#read_buffering?`. ([#6304](https://github.com/crystal-lang/crystal/pull/6304), [#6474](https://github.com/crystal-lang/crystal/pull/6474), thanks @asterite, @bcardiff) - Fixed handling of closed state in `HTTP::Server::Response`. ([#6477](https://github.com/crystal-lang/crystal/pull/6477), thanks @straight-shoota) - Fixed change encoding name comparison to be case insensitive for UTF-8. ([#6355](https://github.com/crystal-lang/crystal/pull/6355), thanks @asterite) - Fixed support for quoted charset value in HTTP. ([#6354](https://github.com/crystal-lang/crystal/pull/6354), thanks @asterite) - Fixed docs regarding udp example on `Socket::Addrinfo`. ([#6388](https://github.com/crystal-lang/crystal/pull/6388), thanks @faustinoaq) - Fixed `HTTP::Client` will set `connection: close` header on one-shot requests. ([#6410](https://github.com/crystal-lang/crystal/pull/6410), thanks @asterite) - Fixed `OpenSSL::Digest` for multibyte strings. ([#6471](https://github.com/crystal-lang/crystal/pull/6471), thanks @RX14) - Fixed missing `Host` header when using `HTTP::Client#exec`. ([#6481](https://github.com/crystal-lang/crystal/pull/6481), thanks @straight-shoota) - Add `HTTP::Server#bind(URI|String)` that infers protocol from scheme. ([#6500](https://github.com/crystal-lang/crystal/pull/6500), thanks @straight-shoota) - Add `HTTP::Params.new` and `HTTP::Params#empty?`. ([#6241](https://github.com/crystal-lang/crystal/pull/6241), thanks @icyleaf) - Add support for multiple Etags in `If-None-Match` header for `HTTP::Request` and `HTTP::StaticFileHandler`. ([#6219](https://github.com/crystal-lang/crystal/pull/6219), thanks @straight-shoota) - Add IDNs normalization to punycode in `OpenSSL::SSL::Socket`. ([#6306](https://github.com/crystal-lang/crystal/pull/6306), thanks @paulkass) - Add `application/wasm` to the default MIME types of `HTTP::StaticFileHandler`. ([#6377](https://github.com/crystal-lang/crystal/pull/6377), thanks @MakeNowJust) - Add `URI#absolute?` and `URI#relative?`. ([#6311](https://github.com/crystal-lang/crystal/pull/6311), thanks @mamantoha) #### Crypto - Fixed `Crypto::Bcrypt::Password#==` was hiding `Reference#==(other)`. ([#6356](https://github.com/crystal-lang/crystal/pull/6356), thanks @straight-shoota) #### Concurrency - Fixed `Atomic#swap` with reference types. ([#6428](https://github.com/crystal-lang/crystal/pull/6428), thanks @Exilor) #### System - Fixed raise `Errno` if `Process.new` fails to exec. ([#6501](https://github.com/crystal-lang/crystal/pull/6501), thanks @straight-shoota, @lbguilherme) - Add support for `WinError` UTF-16 string messages. ([#6442](https://github.com/crystal-lang/crystal/pull/6442), thanks @straight-shoota) - Refactor platform specifics from `ENV` to `Crystal::System::Env` and implement for Windows. ([#6333](https://github.com/crystal-lang/crystal/pull/6333), [#6499](https://github.com/crystal-lang/crystal/pull/6499), thanks @straight-shoota) #### Spec - Add [TAP](https://testanything.org/) formatter to spec suite. ([#6286](https://github.com/crystal-lang/crystal/pull/6286), thanks @straight-shoota) ### Compiler - Fixed named arguments expansion from double splat clash with local variable names. ([#6378](https://github.com/crystal-lang/crystal/pull/6378), thanks @asterite) - Fixed auto assigned ivars arguments expansions when clash with keywords. ([#6379](https://github.com/crystal-lang/crystal/pull/6379), thanks @asterite) - Fixed resulting type of union of tuple metaclasses. ([#6342](https://github.com/crystal-lang/crystal/pull/6342), thanks @asterite) - Fixed ICE when using unbound type parameter inside generic type. ([#6292](https://github.com/crystal-lang/crystal/pull/6292), thanks @asterite) - Fixed ICE when using unions of metaclasses. ([#6307](https://github.com/crystal-lang/crystal/pull/6307), thanks @asterite) - Fixed ICE related to literal type guessing and generic types hierarchy. ([#6341](https://github.com/crystal-lang/crystal/pull/6341), thanks @asterite) - Fixed ICE related to `not` and inlinable values. ([#6452](https://github.com/crystal-lang/crystal/pull/6452), thanks @asterite) - Fixed rebind variables type in while condition after analyzing its body. ([#6295](https://github.com/crystal-lang/crystal/pull/6295), thanks @asterite) - Fixed corner cases regarding automatic casts and method instantiation. ([#6284](https://github.com/crystal-lang/crystal/pull/6284), thanks @asterite) - Fixed parsing of `\A` (and others) inside `%r{...}` inside macros. ([#6282](https://github.com/crystal-lang/crystal/pull/6282), thanks @asterite) - Fixed parsing of of named tuple inside generic type arguments. ([#6413](https://github.com/crystal-lang/crystal/pull/6413), thanks @asterite) - Fixed disallow cast from module class to virtual metaclass. ([#6320](https://github.com/crystal-lang/crystal/pull/6320), thanks @asterite) - Fixed disallow `return` inside a constant's value. ([#6347](https://github.com/crystal-lang/crystal/pull/6347), thanks @asterite) - Fixed debug info for closured self. ([#6346](https://github.com/crystal-lang/crystal/pull/6346), thanks @asterite) - Fixed parsing error of newline before closing macro. ([#6382](https://github.com/crystal-lang/crystal/pull/6382), thanks @asterite) - Fixed missing error if constant has `NoReturn` type. ([#6411](https://github.com/crystal-lang/crystal/pull/6411), thanks @asterite) - Fixed give proper error when doing sizeof uninstantiated generic type. ([#6418](https://github.com/crystal-lang/crystal/pull/6418), thanks @asterite) - Fixed private aliases at top-level are now considered private. ([#6432](https://github.com/crystal-lang/crystal/pull/6432), thanks @asterite) - Fixed setters with multiple arguments as now disallowed. ([#6324](https://github.com/crystal-lang/crystal/pull/6324), thanks @maxfierke) - Fixed type var that resolves to number in restriction didn't work. ([#6504](https://github.com/crystal-lang/crystal/pull/6504), thanks @asterite) - Add support for class variables in generic classes. ([#6348](https://github.com/crystal-lang/crystal/pull/6348), thanks @asterite) - Add support for exception handling in Windows (SEH). ([#6419](https://github.com/crystal-lang/crystal/pull/6419), thanks @RX14) - Refactor codegen of binary operators. ([#6330](https://github.com/crystal-lang/crystal/pull/6330), thanks @bcardiff) - Refactor use `JSON::Serializable` instead of `JSON.mapping`. ([#6308](https://github.com/crystal-lang/crystal/pull/6308), thanks @kostya) - Refactor `Crystal::Call#check_visibility` and extract type methods. ([#6484](https://github.com/crystal-lang/crystal/pull/6484), thanks @asterite, @bcardiff) - Change how metaclasses are shown. Use `Foo.class` instead of `Foo:Class`. ([#6439](https://github.com/crystal-lang/crystal/pull/6439), thanks @RX14) ### Tools - Flatten project structure created by `crystal init`. ([#6317](https://github.com/crystal-lang/crystal/pull/6317), thanks @straight-shoota) #### Formatter - Fixed formatting of `{ {1}.foo, ...}` like expressions. ([#6300](https://github.com/crystal-lang/crystal/pull/6300), thanks @asterite) - Fixed formatting of `when` with numbers. Use right alignment only if all are number literals. ([#6392](https://github.com/crystal-lang/crystal/pull/6392), thanks @MakeNowJust) - Fixed formatting of comment in case's else. ([#6393](https://github.com/crystal-lang/crystal/pull/6393), thanks @MakeNowJust) - Fixed code fence when language is not crystal will not be formatted. ([#6424](https://github.com/crystal-lang/crystal/pull/6424), thanks @asterite) #### Doc generator - Add line numbers at link when there are duplicated filenames in "Defined in:" section. ([#6280](https://github.com/crystal-lang/crystal/pull/6280), [#6489](https://github.com/crystal-lang/crystal/pull/6489), thanks @r00ster91) - Fix docs navigator not scrolling into open type on page load. ([#6420](https://github.com/crystal-lang/crystal/pull/6420), thanks @soanvig) ### Others - Fixed `system_spec` does no longer emit errors messages on BSD platforms. ([#6289](https://github.com/crystal-lang/crystal/pull/6289), thanks @jcs) - Fixed compilation issue when running spec against compiler and std together. ([#6312](https://github.com/crystal-lang/crystal/pull/6312), thanks @straight-shoota) - Add support for LLVM 6.0. ([#6381](https://github.com/crystal-lang/crystal/pull/6381), [#6380](https://github.com/crystal-lang/crystal/pull/6380), [#6383](https://github.com/crystal-lang/crystal/pull/6383), thanks @felixbuenemann) - CI improvements and housekeeping. ([#6313](https://github.com/crystal-lang/crystal/pull/6313), [#6337](https://github.com/crystal-lang/crystal/pull/6337), [#6407](https://github.com/crystal-lang/crystal/pull/6407), [#6408](https://github.com/crystal-lang/crystal/pull/6408), [#6315](https://github.com/crystal-lang/crystal/pull/6315), thanks @bcardiff, @MakeNowJust, @r00ster91, @maiha) ## 0.25.1 (2018-06-27) ### Standard library #### Macros - Fixed `Object.delegate` is now able to be used with `[]=` methods. ([#6178](https://github.com/crystal-lang/crystal/pull/6178), thanks @straight-shoota) - Fixed `p!` `pp!` are now able to be used with tuples. ([#6244](https://github.com/crystal-lang/crystal/pull/6244), thanks @bcardiff) - Add `#copy_with` method to structs generated by `record` macro. ([#5736](https://github.com/crystal-lang/crystal/pull/5736), thanks @chris-baynes) - Add docs for `ArrayLiteral#push` and `#unshift`. ([#6232](https://github.com/crystal-lang/crystal/pull/6232), thanks @MakeNowJust) #### Collections - Add docs for `Indexable#zip` and `#zip?` methods. ([#5734](https://github.com/crystal-lang/crystal/pull/5734), thanks @rodrigopinto) #### Serialization - Add `#dup` and `#clone` for `JSON::Any` and `YAML::Any`. ([6266](https://github.com/crystal-lang/crystal/pull/6266), thanks @asterite) - Add docs example of nesting mappings to `YAML.builder`. ([#6097](https://github.com/crystal-lang/crystal/pull/6097), thanks @kalinon) #### Time - Fixed docs regarding formatting and parsing `Time`. ([#6208](https://github.com/crystal-lang/crystal/pull/6208), [#6214](https://github.com/crystal-lang/crystal/pull/6214), thanks @r00ster91 and @straight-shoota) - Fixed `Time` internals for future Windows support. ([#6181](https://github.com/crystal-lang/crystal/pull/6181), thanks @RX14) - Add `Time::Span#microseconds`, `Int#microseconds` and `Float#microseconds`. ([#6272](https://github.com/crystal-lang/crystal/pull/6272), thanks @asterite) - Add specs. ([#6174](https://github.com/crystal-lang/crystal/pull/6174), thanks @straight-shoota) #### Files - Fixed `File.extname` edge case. ([#6234](https://github.com/crystal-lang/crystal/pull/6234), thanks @bcardiff) - Fixed `FileInfo#flags` return value. ([#6248](https://github.com/crystal-lang/crystal/pull/6248), thanks @fgimian) #### Networking - Fixed `IO#write(slice : Bytes)` won't write information if slice is empty. ([#6269](https://github.com/crystal-lang/crystal/pull/6269), thanks @asterite) - Fixed docs regarding `HTTP::Server#bind_tcp` method. ([#6179](https://github.com/crystal-lang/crystal/pull/6179), [#6233](https://github.com/crystal-lang/crystal/pull/6233), thanks @straight-shoota and @MakeNowJust) - Add Etag support in `HTTP::StaticFileHandler`. ([#6145](https://github.com/crystal-lang/crystal/pull/6145), thanks @emq) #### Misc - Fixed `mmap` usage on OpenBSD 6.3+. ([#6250](https://github.com/crystal-lang/crystal/pull/6250), thanks @jcs) - Fixed `big/big_int`, `big/big_float`, etc are now able to be included directly. ([#6267](https://github.com/crystal-lang/crystal/pull/6267), thanks @asterite) - Refactor dependency in `Crystal::Hasher` to avoid load order issues. ([#6184](https://github.com/crystal-lang/crystal/pull/6184), thanks @ysbaddaden) ### Compiler - Fixed a leakage of unbounded generic type variable and show error. ([#6128](https://github.com/crystal-lang/crystal/pull/6128), thanks @asterite) - Fixed error message when lookup of library fails and lib's name contains non-alpha chars. ([#6187](https://github.com/crystal-lang/crystal/pull/6187), thanks @oprypin) - Fixed integer kind deduction for very large negative numbers. ([#6182](https://github.com/crystal-lang/crystal/pull/6182), thanks @rGradeStd) - Refactor specs tempfiles and data files usage in favor of portability ([#5951](https://github.com/crystal-lang/crystal/pull/5951), thanks @straight-shoota) - Improve formatting and information in some compiler error messages. ([#6261](https://github.com/crystal-lang/crystal/pull/6261), thanks @RX14) ### Tools #### Formatter - Fixed crash when semicolon after block paren were present. ([#6192](https://github.com/crystal-lang/crystal/pull/6192), thanks @MakeNowJust) - Fixed invalid code produced when heredoc and comma were present. ([#6222](https://github.com/crystal-lang/crystal/pull/6222), thanks @straight-shoota and @MakeNowJust) - Fixed crash when one-liner `begin`/`rescue` were present. ([#6274](https://github.com/crystal-lang/crystal/pull/6274), thanks @asterite) #### Doc generator - Fixed JSON export that prevent jumping to constant. ([#6218](https://github.com/crystal-lang/crystal/pull/6218), thanks @straight-shoota) - Fixed crash when virtual types were reached. ([#6246](https://github.com/crystal-lang/crystal/pull/6246), thanks @bcardiff) ### Misc - CI improvements and housekeeping. ([#6193](https://github.com/crystal-lang/crystal/pull/6193), [#6211](https://github.com/crystal-lang/crystal/pull/6211), [#6209](https://github.com/crystal-lang/crystal/pull/6209), [#6221](https://github.com/crystal-lang/crystal/pull/6221), [#6260](https://github.com/crystal-lang/crystal/pull/6260), thanks @bcardiff, @kostya and @r00ster91) - Update man page. ([#6259](https://github.com/crystal-lang/crystal/pull/6259), thanks @docelic) ## 0.25.0 (2018-06-11) ### New features and breaking changes - **(breaking-change)** Time zones has been added to `Time`. ([#5324](https://github.com/crystal-lang/crystal/pull/5324), [#5819](https://github.com/crystal-lang/crystal/pull/5819), thanks @straight-shoota) - **(breaking-change)** Drop `HTTP.rfc1123_date` in favor of `HTTP.format_time` and add time format implementations for ISO-8601, RFC-3339, and RFC-2822. ([#5123](https://github.com/crystal-lang/crystal/pull/5123), thanks @straight-shoota) - **(breaking-change)** `crystal deps` is removed, use `shards`. ([#5544](https://github.com/crystal-lang/crystal/pull/5544), thanks @asterite) - **(breaking-change)** `Hash#key` was renamed as `Hash#key_for`. ([#5444](https://github.com/crystal-lang/crystal/pull/5444), thanks @marksiemers) - **(breaking-change)** `JSON::Any` and `YAML::Any` have been re-implemented solving some inconsistencies and avoiding the usage of recursive aliases (`JSON::Type` and `YAML::Type` have been removed). ([#5183](https://github.com/crystal-lang/crystal/pull/5183), thanks @asterite) - **(breaking-change)** Multiple heredocs can be used as arguments and methods can be invoked writing them in the initial delimiter, also empty heredocs are now supported. ([#5578](https://github.com/crystal-lang/crystal/pull/5578), [#5602](https://github.com/crystal-lang/crystal/pull/5602), [#6048](https://github.com/crystal-lang/crystal/pull/6048), thanks @asterite and @MakeNowJust) - **(breaking-change)** Refactor signal handlers and avoid closing pipe at exit. ([#5730](https://github.com/crystal-lang/crystal/pull/5730), thanks @ysbaddaden) - **(breaking-change)** Improve behaviour of `File.join` with empty path component. ([#5915](https://github.com/crystal-lang/crystal/pull/5915), thanks @straight-shoota) - **(breaking-change)** Drop `Colorize#push` in favor of `Colorize#surround` and allow nested calls across the stack. ([#4196](https://github.com/crystal-lang/crystal/pull/4196), thanks @MakeNowJust) - **(breaking-change)** `File.stat` was renamed to `File.info` and a more portable API was implemented. ([#5584](https://github.com/crystal-lang/crystal/pull/5584), [#6161](https://github.com/crystal-lang/crystal/pull/6161), thanks @RX14 and @bcardiff) - **(breaking-change)** Refactor `HTTP::Server` to bind to multiple addresses. ([#5776](https://github.com/crystal-lang/crystal/pull/5776), [#5959](https://github.com/crystal-lang/crystal/pull/5959), thanks @straight-shoota) - **(breaking-change)** Remove block argument from `loop`. ([#6026](https://github.com/crystal-lang/crystal/pull/6026), thanks @asterite) - **(breaking-change)** Do not collapse unions for sibling types. ([#6024](https://github.com/crystal-lang/crystal/pull/6024), thanks @asterite) - **(breaking-change)** Disallow `typeof` in type restrictions. ([#5192](https://github.com/crystal-lang/crystal/pull/5192), thanks @asterite) - **(breaking-change)** Perform unbuffered read when `IO::Buffered#sync = true`. ([#5849](https://github.com/crystal-lang/crystal/pull/5849), thanks @RX14) - **(breaking-change)** Drop `when _` support. ([#6150](https://github.com/crystal-lang/crystal/pull/6150), thanks @MakeNowJust) - **(breaking-change)** The `DivisionByZero` exception was renamed to `DivisionByZeroError`. ([#5395](https://github.com/crystal-lang/crystal/pull/5395), thanks @sdogruyol) - A bootstrap Windows port has been added to the standard library. It's not usable for real programs yet. ([#5339](https://github.com/crystal-lang/crystal/pull/5339), [#5484](https://github.com/crystal-lang/crystal/pull/5484), [#5448](https://github.com/crystal-lang/crystal/pull/5448), thanks @RX14) - Add automatic casts on literals arguments for numbers and enums. ([#6074](https://github.com/crystal-lang/crystal/pull/6074), thanks @asterite) - Add user defined annotations. ([#6063](https://github.com/crystal-lang/crystal/pull/6063), [#6084](https://github.com/crystal-lang/crystal/pull/6084), [#6106](https://github.com/crystal-lang/crystal/pull/6106), thanks @asterite) - Add macro verbatim blocks to avoid nested macros. ([#6108](https://github.com/crystal-lang/crystal/pull/6108), thanks @asterite) - Allow namespaced expressions to define constants eg: `Foo::Bar = 1`. ([#5883](https://github.com/crystal-lang/crystal/pull/5883), thanks @bew) - Allow trailing `=` in symbol literals. ([#5969](https://github.com/crystal-lang/crystal/pull/5969), thanks @straight-shoota) - Allow redefining `None` to `0` for `@[Flags]` enum. ([#6160](https://github.com/crystal-lang/crystal/pull/6160), thanks @bew) - Suggest possible solutions to failing requires. ([#5487](https://github.com/crystal-lang/crystal/pull/5487), thanks @RX14) - Allow pointers of external C library global variables. ([#4845](https://github.com/crystal-lang/crystal/pull/4845), thanks @larubujo) - Decouple pretty-printing (`pp`) and showing the expression (`!`): `p`, `pp`, `p!`, `pp!`. ([#6044](https://github.com/crystal-lang/crystal/pull/6044), thanks @asterite) - Add ivars default value reflection in macros. ([#5974](https://github.com/crystal-lang/crystal/pull/5974), thanks @asterite) - Add argless overload to `Number#round` to rounds to the nearest whole number. ([#5397](https://github.com/crystal-lang/crystal/pull/5397), thanks @Sija) - Add `Int#bits_set?` to easily check that certain bits are set. ([#5619](https://github.com/crystal-lang/crystal/pull/5619), thanks @RX14) - Add `Float32` and `Float64` constants. ([#4787](https://github.com/crystal-lang/crystal/pull/4787), thanks @konovod) - Add allocated bytes per operation in `Benchmark.ips`. ([#5522](https://github.com/crystal-lang/crystal/pull/5522), thanks @asterite) - Add `String#to_utf16` and `String.from_utf16`. ([#5541](https://github.com/crystal-lang/crystal/pull/5541), [#5579](https://github.com/crystal-lang/crystal/pull/5579), [#5583](https://github.com/crystal-lang/crystal/pull/5583) thanks @asterite, @RX14 and @straight-shoota) - Add `String#starts_with?(re: Regex)`. ([#5485](https://github.com/crystal-lang/crystal/pull/5485), thanks @MakeNowJust) - Add `Regex.needs_escape?`. ([#5962](https://github.com/crystal-lang/crystal/pull/5962), thanks @Sija) - Add `Hash#last_key` and `Hash#last_value`. ([#5760](https://github.com/crystal-lang/crystal/pull/5760), thanks @j8r) - Add no-copy iteration to `Indexable`. ([#4584](https://github.com/crystal-lang/crystal/pull/4584), thanks @cjgajard) - Add `Time#at_{beginning,end}_of_second` ([#6167](https://github.com/crystal-lang/crystal/pull/6167), thanks @straight-shoota) - Add `IO::Stapled` to combine two unidirectional `IO`s into a single bidirectional one. ([#6017](https://github.com/crystal-lang/crystal/pull/6017), thanks @straight-shoota) - Add context to errors in `JSON.mapping` generated code. ([#5932](https://github.com/crystal-lang/crystal/pull/5932), thanks @straight-shoota) - Add `JSON::Serializable` and `YAML::Serializable` attribute powered mappings. ([#6082](https://github.com/crystal-lang/crystal/pull/6082), thanks @kostya) - Add `mode` param to `File.write`. ([#5754](https://github.com/crystal-lang/crystal/pull/5754), thanks @woodruffw) - Add Punycode/IDNA support and integrate with DNS lookup. ([#2543](https://github.com/crystal-lang/crystal/pull/2543), thanks @MakeNowJust) - Add `HTTP::Client#options` method. ([#5824](https://github.com/crystal-lang/crystal/pull/5824), thanks @mamantoha) - Add support for `Last-Modified` and other cache improvements to `HTTP::StaticFileHandler`. ([#2470](https://github.com/crystal-lang/crystal/pull/2470), [#5607](https://github.com/crystal-lang/crystal/pull/5607), thanks @bebac and @straight-shoota) - Add operations and improvements related to `BigDecimal` and `BigFloat`. ([#5437](https://github.com/crystal-lang/crystal/pull/5437), [#5390](https://github.com/crystal-lang/crystal/pull/5390), [#5589](https://github.com/crystal-lang/crystal/pull/5589), [#5582](https://github.com/crystal-lang/crystal/pull/5582), [#5638](https://github.com/crystal-lang/crystal/pull/5638), [#5675](https://github.com/crystal-lang/crystal/pull/5675), thanks @Sija and @mjago) - Add `BigDecimal` and `UUID` JSON support. ([#5525](https://github.com/crystal-lang/crystal/pull/5525), [#5551](https://github.com/crystal-lang/crystal/pull/5551), thanks @lukeasrodgers and @lachlan) - Add missing `UUID#inspect`. ([#5574](https://github.com/crystal-lang/crystal/pull/5574), thanks @ngsankha) - Add `Logger` configuration in initializer. ([#5618](https://github.com/crystal-lang/crystal/pull/5618), thanks @Sija) - Add custom separators in `CSV.build`. ([#5998](https://github.com/crystal-lang/crystal/pull/5998), [#6008](https://github.com/crystal-lang/crystal/pull/6008) thanks @Sija) - Add `INI.build` to emit `INI` files. ([#5298](https://github.com/crystal-lang/crystal/pull/5298), thanks @j8r) - Add `Process.chroot`. ([#5577](https://github.com/crystal-lang/crystal/pull/5577), thanks @chris-huxtable) - Add `Tempfile.tempname` to create likely nonexisting filenames. ([#5360](https://github.com/crystal-lang/crystal/pull/5360), thanks @woodruffw) - Add `FileUtils#ln`, `ln_s`, and `ln_sf`. ([#5421](https://github.com/crystal-lang/crystal/pull/5421), thanks @woodruffw) - Add support 8bit and true color to `Colorize`. ([#5902](https://github.com/crystal-lang/crystal/pull/5902), thanks @MakeNowJust) - Add comparison operators between classes. ([#5645](https://github.com/crystal-lang/crystal/pull/5645), thanks @asterite) - Add exception cause in backtrace. ([#5833](https://github.com/crystal-lang/crystal/pull/5833), thanks @RX14) - Add unhandled exception as argument in `at_exit`. ([#5906](https://github.com/crystal-lang/crystal/pull/5906), thanks @MakeNowJust) - Add support to target aarch64-linux-musl. ([#5861](https://github.com/crystal-lang/crystal/pull/5861), thanks @jirutka) - Add `#clear` method to `ArrayLiteral`/`HashLiteral` for macros. ([#5265](https://github.com/crystal-lang/crystal/pull/5265), thanks @Sija) - Add `Bool#to_unsafe` for C bindings. ([#5465](https://github.com/crystal-lang/crystal/pull/5465), thanks @woodruffw) - Spec: Add expectations `starts_with`, `ends_with`. ([#5881](https://github.com/crystal-lang/crystal/pull/5881), thanks @kostya) - Formatter: Add `--include` and `--exclude` options to restrict directories. ([#4635](https://github.com/crystal-lang/crystal/pull/4635), thanks @straight-shoota) - Documentation generator: improved navigation, searching, rendering and SEO. ([#5229](https://github.com/crystal-lang/crystal/pull/5229), [#5795](https://github.com/crystal-lang/crystal/pull/5795), [#5990](https://github.com/crystal-lang/crystal/pull/5990), [#5657](https://github.com/crystal-lang/crystal/pull/5657), [#6073](https://github.com/crystal-lang/crystal/pull/6073), thanks @straight-shoota, @Sija and @j8r) - Playground: Add button in playground to run formatter. ([#3652](https://github.com/crystal-lang/crystal/pull/3652), thanks @samueleaton) ### Standard library bugs fixed - Fixed `String#sub` handling of negative indexes. ([#5491](https://github.com/crystal-lang/crystal/pull/5491), thanks @MakeNowJust) - Fixed `String#gsub` in non-ascii strings. ([#5350](https://github.com/crystal-lang/crystal/pull/5350), thanks @straight-shoota) - Fixed `String#dump` for UTF-8 characters higher than `\uFFFF`. ([#5668](https://github.com/crystal-lang/crystal/pull/5668), thanks @straight-shoota) - Fixed `String#tr` edge case optimization bug. ([#5913](https://github.com/crystal-lang/crystal/pull/5913), thanks @MakeNowJust) - Fixed `String#rindex` when called with `Regex`. ([#5594](https://github.com/crystal-lang/crystal/pull/5594), thanks @straight-shoota) - Fixed `Time::Span` precision loss and boundary check. ([#5563](https://github.com/crystal-lang/crystal/pull/5563), [#5786](https://github.com/crystal-lang/crystal/pull/5786), thanks @petoem and @straight-shoota) - `Array#sample` was fixed to use the provided random number generator (instead of the default) in all cases. ([#5419](https://github.com/crystal-lang/crystal/pull/5419), thanks @c910335) - Add short-circuit logic in `Deque#rotate!` for singleton and empty queues. ([#5399](https://github.com/crystal-lang/crystal/pull/5399), thanks @willcosgrove) - `Slice#reverse!` was optimised to be up to 43% faster. ([#5401](https://github.com/crystal-lang/crystal/pull/5401), thanks @larubujo) - Fixed `Regex#inspect` when escaping was needed. ([#5841](https://github.com/crystal-lang/crystal/pull/5841), thanks @MakeNowJust) - Fixed `JSON.mapping` now generates type restriction on getters. ([#5935](https://github.com/crystal-lang/crystal/pull/5935), thanks @Daniel-Worrall) - Fixed `JSON.mapping` documentation regarding unions. ([#5483](https://github.com/crystal-lang/crystal/pull/5483), thanks @RX14) - Fixed `JSON.mapping` and `YAML.mapping` to allow `properties` property. ([#5180](https://github.com/crystal-lang/crystal/pull/5180), [#5352](https://github.com/crystal-lang/crystal/pull/5352), thanks @maxpowa and @Sija) - Fixed `YAML` int and float parsing. ([#5699](https://github.com/crystal-lang/crystal/pull/5699), [#5774](https://github.com/crystal-lang/crystal/pull/5774), thanks @straight-shoota) - Fixed WebSocket handshake validation. ([#5327](https://github.com/crystal-lang/crystal/pull/5327), [#6027](https://github.com/crystal-lang/crystal/pull/6027) thanks @straight-shoota) - Fixed `HTTP::Client` is able to use ipv6 addresses. ([#6147](https://github.com/crystal-lang/crystal/pull/6147), thanks @bcardiff) - Fixed handling some invalid responses in `HTTP::Client`. ([#5630](https://github.com/crystal-lang/crystal/pull/5630), thanks @straight-shoota) - Fixed `HTTP::ChunkedContent` will raise on unterminated content. ([#5928](https://github.com/crystal-lang/crystal/pull/5928), [#5943](https://github.com/crystal-lang/crystal/pull/5943), thanks @straight-shoota) - `URI#to_s` now handles default ports for lots of schemes. ([#5233](https://github.com/crystal-lang/crystal/pull/5233), thanks @lachlan) - `HTTP::Cookies` is able to deal with spaces in cookies. ([#5408](https://github.com/crystal-lang/crystal/pull/5408), thanks @bararchy) - Fixed MIME type of SVG images in `HTTP::StaticFileHandler`. ([#5605](https://github.com/crystal-lang/crystal/pull/5605), thanks @damianham) - Fixed URI encoding in `StaticFileHandler#redirect_to`. ([#5628](https://github.com/crystal-lang/crystal/pull/5628), thanks @straight-shoota) - Fixed `before_request` callbacks to be executed right before writing the request in `HTTP::Client`. ([#5626](https://github.com/crystal-lang/crystal/pull/5626), thanks @asterite) - `Dir.glob` was re-implemented with performance improvements and edge cases fixed. ([#5179](https://github.com/crystal-lang/crystal/pull/5179), thanks @straight-shoota) - Fixed `File.extname` edge case for '.' in path with no extension. ([#5790](https://github.com/crystal-lang/crystal/pull/5790), thanks @codyjb) - Some ECDHE curves were incorrectly disabled in `OpenSSL` clients, this has been fixed. ([#5494](https://github.com/crystal-lang/crystal/pull/5494), thanks @jhass) - Fixed allow bcrypt passwords up to 71 bytes. ([#5356](https://github.com/crystal-lang/crystal/pull/5356), thanks @ysbaddaden) - Unhandled exceptions occurring inside `Process.fork` now print their backtrace correctly. ([#5431](https://github.com/crystal-lang/crystal/pull/5431), thanks @RX14) - Fixed `Zip` no longer modifies deflate signature. ([#5376](https://github.com/crystal-lang/crystal/pull/5376), thanks @luislavena) - Fixed `INI` parser edge cases and performance improvements. ([#5442](https://github.com/crystal-lang/crystal/pull/5442), [#5718](https://github.com/crystal-lang/crystal/pull/5718) thanks @woodruffw, @j8r) - Fixed initialization of `LibXML`. ([#5587](https://github.com/crystal-lang/crystal/pull/5587), thanks @lbguilherme) - Some finalizers were missing for example when the object where cloned. ([#5367](https://github.com/crystal-lang/crystal/pull/5367), thanks @alexbatalov) - Fixed segfault handler initialization regarding `sa_mask`. ([#5677](https://github.com/crystal-lang/crystal/pull/5677) thanks @ysbaddaden) - Fixed missing reference symbol in ARM. ([#5640](https://github.com/crystal-lang/crystal/pull/5640), thanks @blankoworld) - Fixed detect LLVM 5.0 by `llvm-config-5.0` command. ([#5531](https://github.com/crystal-lang/crystal/pull/5531), thanks @Vexatos) - Restore STDIN|OUT|ERR blocking state on exit. ([#5802](https://github.com/crystal-lang/crystal/pull/5802), thanks @bew) - Fixed multiple `at_exit` handlers chaining. ([#5413](https://github.com/crystal-lang/crystal/pull/5413), thanks @bew) - Fixed senders were not notified when channels were closed. ([#5880](https://github.com/crystal-lang/crystal/pull/5880), thanks @carlhoerberg) - Fixed forward unhandled exception to caller in `parallel` macro. ([#5726](https://github.com/crystal-lang/crystal/pull/5726), thanks @lipanski) - Fixed Markdown parsing of code fences appearing on the same line. ([#5606](https://github.com/crystal-lang/crystal/pull/5606), thanks @oprypin) - Fixed OpenSSL bindings to recognize LibreSSL. ([#5676](https://github.com/crystal-lang/crystal/pull/5676), [#6062](https://github.com/crystal-lang/crystal/pull/6062), [#5949](https://github.com/crystal-lang/crystal/pull/5949), [#5973](https://github.com/crystal-lang/crystal/pull/5973) thanks @LVMBDV and @RX14) - Fixed path value in to `UNIXSocket` created by `UNIXServer`. ([#5869](https://github.com/crystal-lang/crystal/pull/5869), thanks @straight-shoota) - Fixed `Object.delegate` over setters. ([#5964](https://github.com/crystal-lang/crystal/pull/5964), thanks @straight-shoota) - Fixed `pp` will now use the same width on every line. ([#5978](https://github.com/crystal-lang/crystal/pull/5978), thanks @MakeNowJust) - Fixes missing stdarg.cr for i686-linux-musl. ([#6120](https://github.com/crystal-lang/crystal/pull/6120), thanks @bcardiff) - Spec: Fixed junit spec formatter to emit the correct XML. ([#5463](https://github.com/crystal-lang/crystal/pull/5463), thanks @hanneskaeufler) ### Compiler bugs fixed - Fixed enum generated values when a member has value 0. ([#5954](https://github.com/crystal-lang/crystal/pull/5954), thanks @bew) - Fixed compiler issue when previous compilation was interrupted. ([#5585](https://github.com/crystal-lang/crystal/pull/5585), thanks @asterite) - Fixed compiler error with an empty `ensure` block. ([#5396](https://github.com/crystal-lang/crystal/pull/5396), thanks @MakeNowJust) - Fixed parsing regex in default arguments. ([#5481](https://github.com/crystal-lang/crystal/pull/5481), thanks @MakeNowJust) - Fixed parsing error of regex literal after open parenthesis. ([#5453](https://github.com/crystal-lang/crystal/pull/5453), thanks @MakeNowJust) - Fixed parsing of empty array with blank. ([#6107](https://github.com/crystal-lang/crystal/pull/6107), thanks @asterite) - Static libraries are now found correctly when using the `--static` compiler flag. ([#5385](https://github.com/crystal-lang/crystal/pull/5385), thanks @jreinert) - Improve error messages for unterminated literals. ([#5409](https://github.com/crystal-lang/crystal/pull/5409), thanks @straight-shoota) - Fixed `ProcNotation` and `ProcLiteral` introspection in macros. ([#5206](https://github.com/crystal-lang/crystal/pull/5206), thanks @javanut13) - Cross compilation honors `--emit` and avoid generating `bc_flags` in current directory. ([#5521](https://github.com/crystal-lang/crystal/pull/5521), thanks @asterite) - Fixed compiler error with integer constants as generic arguments. ([#5532](https://github.com/crystal-lang/crystal/pull/5532), thanks @asterite) - Fixed compiler error with self as base class. ([#5534](https://github.com/crystal-lang/crystal/pull/5534), thanks @asterite) - Fixed macro expansion when mutating the argument. ([#5247](https://github.com/crystal-lang/crystal/pull/5247), thanks @MakeNowJust) - Fixed macro expansion edge cases. ([#5680](https://github.com/crystal-lang/crystal/pull/5680), [#5842](https://github.com/crystal-lang/crystal/pull/5842), [#6163](https://github.com/crystal-lang/crystal/pull/6163), thanks @asterite, @MakeNowJust and @splattael) - Fixed macro overload on named args. ([#5808](https://github.com/crystal-lang/crystal/pull/5808), thanks @bew) - Fixed macro numeric types used in interpreter. ([#5972](https://github.com/crystal-lang/crystal/pull/5972), thanks @straight-shoota) - Fixed missing debug locations in several places. ([#5597](https://github.com/crystal-lang/crystal/pull/5597), thanks @asterite) - Fixed missing information in AST nodes needed for macro expansion. ([#5454](https://github.com/crystal-lang/crystal/pull/5454), thanks @MakeNowJust) - Fixed multiline error messages in emitted by `ASTNode#raise` macro method. ([#5670](https://github.com/crystal-lang/crystal/pull/5670), thanks @asterite) - Fixed nested delimiters and escaped whitespace in string/symbol array literals. ([#5667](https://github.com/crystal-lang/crystal/pull/5667), thanks @straight-shoota) - Fixed custom array/hash-like literals in nested modules. ([#5685](https://github.com/crystal-lang/crystal/pull/5685), thanks @asterite) - Fixed usage of static array in C externs. ([#5690](https://github.com/crystal-lang/crystal/pull/5690), thanks @asterite) - Fixed `spawn` over expression with receivers. ([#5781](https://github.com/crystal-lang/crystal/pull/5781), thanks @straight-shoota) - Fixed prevent heredoc inside interpolation. ([#5648](https://github.com/crystal-lang/crystal/pull/5648), thanks @MakeNowJust) - Fixed parsing error when a newline follows block arg. ([#5737](https://github.com/crystal-lang/crystal/pull/5737), thanks @bew) - Fixed parsing error when macro argument is followed by a newline. ([#6046](https://github.com/crystal-lang/crystal/pull/6046), thanks @asterite) - Fixed compiler error messages wording. ([#5887](https://github.com/crystal-lang/crystal/pull/5887), thanks @r00ster91) - Fixed recursion issues in `method_added` macro hook. ([#5159](https://github.com/crystal-lang/crystal/pull/5159), thanks @MakeNowJust) - Fixed avoid using type of updated argument for type inference. ([#5166](https://github.com/crystal-lang/crystal/pull/5166), thanks @MakeNowJust) - Fixed parsing error message on unbalanced end brace in macros. ([#5420](https://github.com/crystal-lang/crystal/pull/5420), thanks @MakeNowJust) - Fixed parsing error message on keywords are used as arguments. ([#5930](https://github.com/crystal-lang/crystal/pull/5930), [#6052](https://github.com/crystal-lang/crystal/pull/6052), thanks @MakeNowJust and @esse) - Fixed parsing error message on missing comma for named tuples. ([#5981](https://github.com/crystal-lang/crystal/pull/5981), thanks @MakeNowJust) - Fixed missing handling of `cond` node in visitor. ([#6032](https://github.com/crystal-lang/crystal/pull/6032), thanks @veelenga) - Fixed cli when `--threads` has invalid value. ([#6039](https://github.com/crystal-lang/crystal/pull/6039), thanks @r00ster91) - Fixed private methods can now be called with explicit `self` receiver. ([#6075](https://github.com/crystal-lang/crystal/pull/6075), thanks @MakeNowJust) - Fixed missing some missing rules of initializer in initializers macro methods. ([#6077](https://github.com/crystal-lang/crystal/pull/6077), thanks @asterite) - Fixed regression bug related to unreachable code. ([#6045](https://github.com/crystal-lang/crystal/pull/6045), thanks @asterite) ### Tools bugs fixed - Several `crystal init` and template improvements. ([#5475](https://github.com/crystal-lang/crystal/pull/5475), [#5355](https://github.com/crystal-lang/crystal/pull/5355), [#4691](https://github.com/crystal-lang/crystal/pull/4691), [#5788](https://github.com/crystal-lang/crystal/pull/5788), [#5644](https://github.com/crystal-lang/crystal/pull/5644), [#6031](https://github.com/crystal-lang/crystal/pull/6031) thanks @woodruffw, @faustinoaq, @bew, @kostya and @MakeNowJust) - Formatter: improve formatting of method call arguments with trailing comments. ([#5492](https://github.com/crystal-lang/crystal/pull/5492), thanks @MakeNowJust) - Formatter: fix formatting of multiline statements. ([#5234](https://github.com/crystal-lang/crystal/pull/5234), [#5901](https://github.com/crystal-lang/crystal/pull/5901), [#6013](https://github.com/crystal-lang/crystal/pull/6013) thanks @MakeNowJust) - Formatter: fix formatting of multi assignment. ([#5452](https://github.com/crystal-lang/crystal/pull/5452), thanks @MakeNowJust) - Formatter: fix formatting of backslash ending statements. ([#5194](https://github.com/crystal-lang/crystal/pull/5194), thanks @asterite) - Formatter: fix formatting of `.[]` methods. ([#5424](https://github.com/crystal-lang/crystal/pull/5424), thanks @MakeNowJust) - Formatter: fix formatting of statements with comments. ([#5655](https://github.com/crystal-lang/crystal/pull/5655), [#5893](https://github.com/crystal-lang/crystal/pull/5893), [#5909](https://github.com/crystal-lang/crystal/pull/5909), thanks @MakeNowJust) - Formatter: fix formatting of nested `begin`/`end`. ([#5922](https://github.com/crystal-lang/crystal/pull/5922), thanks @MakeNowJust) - Formatter: fix formatting of trailing comma with block calls. ([#5855](https://github.com/crystal-lang/crystal/pull/5855), thanks @MakeNowJust) - Formatter: fix formatting of ending expression after heredoc. ([#6127](https://github.com/crystal-lang/crystal/pull/6127), thanks @asterite) - Documentation generator: references to nested types in markdown are now correctly parsed. ([#5308](https://github.com/crystal-lang/crystal/pull/5308), thanks @straight-shoota) - Documentation generator: fix leftovers regarding default old `doc` directory. ([#5406](https://github.com/crystal-lang/crystal/pull/5406), thanks @GloverDonovan) - Documentation generator: avoid failing on non git directory. ([#3700](https://github.com/crystal-lang/crystal/pull/3700), thanks @MakeNowJust) - `Crystal::Doc::Highlighter` has specs now ([#5368](https://github.com/crystal-lang/crystal/pull/5368), thanks @MakeNowJust) - Playground: can now be run with HTTPS. ([#5527](https://github.com/crystal-lang/crystal/pull/5527), thanks @opiation) - Playground: Pretty-print objects in inspector. ([#4601](https://github.com/crystal-lang/crystal/pull/4601), thanks @jgaskins) ### Misc - The platform-specific parts of `File` and `IO::FileDescriptor` were moved to `Crystal::System`, as part of preparation for the Windows port. ([#5333](https://github.com/crystal-lang/crystal/pull/5333), [#5553](https://github.com/crystal-lang/crystal/pull/5553), [#5622](https://github.com/crystal-lang/crystal/pull/5622) thanks @RX14) - The platform-specific parts of `Dir` were moved to `Crystal::System`, as part of preparation for the Windows port. ([#5447](https://github.com/crystal-lang/crystal/pull/5447), thanks @RX14) - Incremental contributions regarding Windows support. ([#5422](https://github.com/crystal-lang/crystal/pull/5422), [#5524](https://github.com/crystal-lang/crystal/pull/5524), [#5533](https://github.com/crystal-lang/crystal/pull/5533), [#5538](https://github.com/crystal-lang/crystal/pull/5538), [#5539](https://github.com/crystal-lang/crystal/pull/5539), [#5580](https://github.com/crystal-lang/crystal/pull/5580), [#5947](https://github.com/crystal-lang/crystal/pull/5947) thanks @RX14 and @straight-shoota) - The build on OpenBSD was fixed. ([#5387](https://github.com/crystal-lang/crystal/pull/5387), thanks @wmoxam) - Add support for FreeBSD 12 (64-bit inodes). ([#5199](https://github.com/crystal-lang/crystal/pull/5199), thanks @myfreeweb) - Scripts and makefiles now depend on `sh` instead of `bash` for greater portability. ([#5468](https://github.com/crystal-lang/crystal/pull/5468), thanks @j8r) - Honor `LDFLAGS` and `EXTRA_FLAGS` in `Makefile`. ([#5423](https://github.com/crystal-lang/crystal/pull/5423), [#5860](https://github.com/crystal-lang/crystal/pull/5860), thanks @trofi, @jirutka) - Improve message on link failure. ([#5486](https://github.com/crystal-lang/crystal/pull/5486), [#5603](https://github.com/crystal-lang/crystal/pull/5603), thanks @RX14 and @waj) - Improve `String#to_json` when chars don't need escaping. ([#5456](https://github.com/crystal-lang/crystal/pull/5456), thanks @larubujo) - Improve `Time#add_span` when arguments are zero. ([#5787](https://github.com/crystal-lang/crystal/pull/5787), thanks @straight-shoota) - Improve `String#pretty_print` to output by splitting newline. ([#5750](https://github.com/crystal-lang/crystal/pull/5750), thanks @MakeNowJust) - Add `\a` escape sequence. ([#5864](https://github.com/crystal-lang/crystal/pull/5864), thanks @r00ster91) - Several miscellaneous minor code cleanups and refactors. ([#5499](https://github.com/crystal-lang/crystal/pull/5499), [#5502](https://github.com/crystal-lang/crystal/pull/5502), [#5507](https://github.com/crystal-lang/crystal/pull/5507), [#5516](https://github.com/crystal-lang/crystal/pull/5516), [#4915](https://github.com/crystal-lang/crystal/pull/4915), [#5526](https://github.com/crystal-lang/crystal/pull/5526), [#5529](https://github.com/crystal-lang/crystal/pull/5529), [#5535](https://github.com/crystal-lang/crystal/pull/5535), [#5537](https://github.com/crystal-lang/crystal/pull/5537), [#5540](https://github.com/crystal-lang/crystal/pull/5540), [#5435](https://github.com/crystal-lang/crystal/pull/5435), [#5520](https://github.com/crystal-lang/crystal/pull/5520), [#5530](https://github.com/crystal-lang/crystal/pull/5530), [#5547](https://github.com/crystal-lang/crystal/pull/5547), [#5543](https://github.com/crystal-lang/crystal/pull/5543), [#5561](https://github.com/crystal-lang/crystal/pull/5561), [#5599](https://github.com/crystal-lang/crystal/pull/5599), [#5493](https://github.com/crystal-lang/crystal/pull/5493), [#5546](https://github.com/crystal-lang/crystal/pull/5546), [#5624](https://github.com/crystal-lang/crystal/pull/5624), [#5701](https://github.com/crystal-lang/crystal/pull/5701), [#5733](https://github.com/crystal-lang/crystal/pull/5733), [#5646](https://github.com/crystal-lang/crystal/pull/5646), [#5729](https://github.com/crystal-lang/crystal/pull/5729), [#5791](https://github.com/crystal-lang/crystal/pull/5791), [#5859](https://github.com/crystal-lang/crystal/pull/5859), [#5882](https://github.com/crystal-lang/crystal/pull/5882), [#5899](https://github.com/crystal-lang/crystal/pull/5899), [#5918](https://github.com/crystal-lang/crystal/pull/5918), [#5896](https://github.com/crystal-lang/crystal/pull/5896), [#5810](https://github.com/crystal-lang/crystal/pull/5810), [#5575](https://github.com/crystal-lang/crystal/pull/5575), [#5785](https://github.com/crystal-lang/crystal/pull/5785), [#5866](https://github.com/crystal-lang/crystal/pull/5866), [#5816](https://github.com/crystal-lang/crystal/pull/5816), [#5945](https://github.com/crystal-lang/crystal/pull/5945), [#5963](https://github.com/crystal-lang/crystal/pull/5963), [#5968](https://github.com/crystal-lang/crystal/pull/5968), [#5977](https://github.com/crystal-lang/crystal/pull/5977), [#6004](https://github.com/crystal-lang/crystal/pull/6004), [#5794](https://github.com/crystal-lang/crystal/pull/5794), [#5858](https://github.com/crystal-lang/crystal/pull/5858), [#6033](https://github.com/crystal-lang/crystal/pull/6033), [#6036](https://github.com/crystal-lang/crystal/pull/6036), [#6079](https://github.com/crystal-lang/crystal/pull/6079), [#6111](https://github.com/crystal-lang/crystal/pull/6111), [#6118](https://github.com/crystal-lang/crystal/pull/6118), [#6141](https://github.com/crystal-lang/crystal/pull/6141), [#6142](https://github.com/crystal-lang/crystal/pull/6142), [#5380](https://github.com/crystal-lang/crystal/pull/5380), [#6071](https://github.com/crystal-lang/crystal/pull/6071), thanks @chastell, @lachlan, @bew, @RX14, @sdogruyol, @MakeNowJust, @Sija, @noriyotcp, @asterite, @splattael, @straight-shoota, @r00ster91, @jirutka, @paulcsmith, @rab, @esse, @carlhoerberg, @chris-huxtable, @luislavena) - Several documentation fixes and additions. ([#5425](https://github.com/crystal-lang/crystal/pull/5425), [#5682](https://github.com/crystal-lang/crystal/pull/5682), [#5779](https://github.com/crystal-lang/crystal/pull/5779), [#5576](https://github.com/crystal-lang/crystal/pull/5576), [#5806](https://github.com/crystal-lang/crystal/pull/5806), [#5817](https://github.com/crystal-lang/crystal/pull/5817), [#5873](https://github.com/crystal-lang/crystal/pull/5873), [#5878](https://github.com/crystal-lang/crystal/pull/5878), [#5637](https://github.com/crystal-lang/crystal/pull/5637), [#5885](https://github.com/crystal-lang/crystal/pull/5885), [#5884](https://github.com/crystal-lang/crystal/pull/5884), [#5728](https://github.com/crystal-lang/crystal/pull/5728), [#5917](https://github.com/crystal-lang/crystal/pull/5917), [#5912](https://github.com/crystal-lang/crystal/pull/5912), [#5894](https://github.com/crystal-lang/crystal/pull/5894), [#5933](https://github.com/crystal-lang/crystal/pull/5933), [#5809](https://github.com/crystal-lang/crystal/pull/5809), [#5936](https://github.com/crystal-lang/crystal/pull/5936), [#5908](https://github.com/crystal-lang/crystal/pull/5908), [#5851](https://github.com/crystal-lang/crystal/pull/5851), [#5378](https://github.com/crystal-lang/crystal/pull/5378), [#5914](https://github.com/crystal-lang/crystal/pull/5914), [#5967](https://github.com/crystal-lang/crystal/pull/5967), [#5993](https://github.com/crystal-lang/crystal/pull/5993), [#3482](https://github.com/crystal-lang/crystal/pull/3482), [#5946](https://github.com/crystal-lang/crystal/pull/5946), [#6095](https://github.com/crystal-lang/crystal/pull/6095), [#6117](https://github.com/crystal-lang/crystal/pull/6117), [#6131](https://github.com/crystal-lang/crystal/pull/6131), [#6162](https://github.com/crystal-lang/crystal/pull/6162), thanks @MakeNowJust, @straight-shoota, @vendethiel, @bew, @Heaven31415, @marksiemers, @Willamin, @r00ster91, @maiha, @Givralix, @docelic, @CaDs, @esse, @igneus, @masukomi) - CI housekeeping and including 32 bits automated builds. ([#5796](https://github.com/crystal-lang/crystal/pull/5796), [#5804](https://github.com/crystal-lang/crystal/pull/5804), [#5837](https://github.com/crystal-lang/crystal/pull/5837), [#6015](https://github.com/crystal-lang/crystal/pull/6015), [#6165](https://github.com/crystal-lang/crystal/pull/6165), thanks @bcardiff, @bew and @Sija) - Sync docs in master to [https://crystal-lang.org/api/master](https://crystal-lang.org/api/master). ([#5941](https://github.com/crystal-lang/crystal/pull/5941), thanks @bcardiff) - Enable the large heap configuration for libgc. ([#5839](https://github.com/crystal-lang/crystal/pull/5839), thanks @RX14) - Improve Ctrl-C handling of spec. ([#5719](https://github.com/crystal-lang/crystal/pull/5719), thanks @MakeNowJust) - Playground: Update to codemirror 5.38.0. ([#6166](https://github.com/crystal-lang/crystal/pull/6166), thanks @bcardiff) ## 0.24.2 (2018-03-08) - Fixed an `Index out of bounds` raised during `at_exit` ([#5224](https://github.com/crystal-lang/crystal/issues/5224), [#5565](https://github.com/crystal-lang/crystal/issues/5565), thanks @ysbaddaden) - Re-add `Dir#each` so it complies with `Enumerable` ([#5458](https://github.com/crystal-lang/crystal/issues/5458), thanks @bcardiff) - Fixed `SSL::Context` bug verifying certificates ([#5266](https://github.com/crystal-lang/crystal/issues/5266), [#5601](https://github.com/crystal-lang/crystal/issues/5601), thanks @waj) - Fixed UUID documentation that was missing ([#5478](https://github.com/crystal-lang/crystal/issues/5478), [#5542](https://github.com/crystal-lang/crystal/issues/5542), thanks @asterite) - Fixed a bug with single expressions in parenthesis ([#5482](https://github.com/crystal-lang/crystal/issues/5482), [#5511](https://github.com/crystal-lang/crystal/issues/5511), [#5513](https://github.com/crystal-lang/crystal/issues/5513), thanks @MakeNowJust) - Fixed `skip_file` macro docs ([#5488](https://github.com/crystal-lang/crystal/issues/5488), thanks @straight-shoota) - Fixed CI `build` script's `LIBRARY_PATH` ([#5457](https://github.com/crystal-lang/crystal/issues/5457), [#5461](https://github.com/crystal-lang/crystal/issues/5461), thanks @bcardiff) - Fixed formatter bug with upper-cased `fun` names ([#5432](https://github.com/crystal-lang/crystal/issues/5432), [#5434](https://github.com/crystal-lang/crystal/issues/5434), thanks @bew) ## 0.24.1 (2017-12-23) ### New features - Add ThinLTO support for faster release builds in LLVM 4.0 and above. ([#4367](https://github.com/crystal-lang/crystal/issues/4367), thanks @bcardiff) - **(breaking-change)** Add `UUID` type. `Random::Secure.uuid` has been replaced with `UUID.random`. ([#4453](https://github.com/crystal-lang/crystal/issues/4453), thanks @wontruefree) - Add a `BigDecimal` class for arbitrary precision, exact, decimal numbers. ([#4876](https://github.com/crystal-lang/crystal/issues/4876) and [#5255](https://github.com/crystal-lang/crystal/issues/5255), thanks @vegai and @Sija) - Allow `Set` to work as a case condition, which matches when the case variable is inside the set. ([#5269](https://github.com/crystal-lang/crystal/issues/5269), thanks @MakeNowJust) - **(breaking-change)** Change `Time::Format` codes to allow more robust options for parsing sub-second precision times. ([#5317](https://github.com/crystal-lang/crystal/issues/5317), thanks @bcardiff) - Add `Time.utc`, an alias of `Time.new` which shortens creating UTC times. ([#5321](https://github.com/crystal-lang/crystal/issues/5321), thanks @straight-shoota) - Add custom extension support to `Tempfile`. ([#5264](https://github.com/crystal-lang/crystal/issues/5264), thanks @jreinert) - Add `reduce` method to `TupleLiteral` and `ArrayLiteral` when using macros. ([#5294](https://github.com/crystal-lang/crystal/issues/5294), thanks @javanut13) - Export a JSON representation of the documentation in the generated output. ([#4746](https://github.com/crystal-lang/crystal/issues/4746) and [#5228](https://github.com/crystal-lang/crystal/issues/5228), thanks @straight-shoota) - Make `gc/none` garbage collection compile again and allow it to be enabled using `-Dgc_none` compiler flag. ([#5314](https://github.com/crystal-lang/crystal/issues/5314), thanks @ysbaddaden) ### Standard library bugs fixed - Make `String#[]` unable to read out-of-bounds when the string ends in a unicode character. ([#5257](https://github.com/crystal-lang/crystal/issues/5257), thanks @Papierkorb) - Fix incorrect parsing of long JSON floating point values. ([#5323](https://github.com/crystal-lang/crystal/issues/5323), thanks @benoist) - Replace the default hash function with one resistant to hash DoS. ([#5146](https://github.com/crystal-lang/crystal/issues/5146), thanks @funny-falcon) - Ensure equal numbers always have the same hashcode. ([#5276](https://github.com/crystal-lang/crystal/issues/5276), thanks @akzhan) - Fix struct equality when two structs descend from the same abstract struct. ([#5254](https://github.com/crystal-lang/crystal/issues/5254), thanks @hinrik) - Fix `URI#full_path` not to append a `?` unless the query params are nonempty. ([#5340](https://github.com/crystal-lang/crystal/issues/5340), thanks @paulcsmith) - Fix `HTTP::Params.parse` to parse `&&` correctly. ([#5274](https://github.com/crystal-lang/crystal/issues/5274), thanks @akiicat) - Disallow null bytes in `ENV` keys and values. ([#5216](https://github.com/crystal-lang/crystal/issues/5216), thanks @Papierkorb) - Disallow null bytes in `XML::Node` names and content. ([#5200](https://github.com/crystal-lang/crystal/issues/5200), thanks @RX14) - Fix `IO#blocking=` on OpenBSD. ([#5283](https://github.com/crystal-lang/crystal/issues/5283), thanks @wmoxam) - Fix linking programs in OpenBSD. ([#5282](https://github.com/crystal-lang/crystal/issues/5282), thanks @wmoxam) ### Compiler bugs fixed - Stop incorrectly finding top-level methods when searching for a `super` method. ([#5202](https://github.com/crystal-lang/crystal/issues/5202), thanks @lbguilherme) - Fix parsing regex literals starting with a `;` directly after a call (ex `p /;/`). ([#5208](https://github.com/crystal-lang/crystal/issues/5208), thanks @MakeNowJust) - Correct a case where `Expressions#to_s` could produce invalid output, causing macro expansion to fail. ([#5226](https://github.com/crystal-lang/crystal/issues/5226), thanks @asterite) - Give error instead of crashing when `self` is used at the top level. ([#5227](https://github.com/crystal-lang/crystal/issues/5227), thanks @MakeNowJust) - Give error instead of crashing when using `instance_sizeof` on a generic type without providing it's type arguments. ([#5209](https://github.com/crystal-lang/crystal/issues/5209), thanks @lbguilherme) - Fix parsing calls when short block syntax (`&.foo`) is followed by a newline. ([#5237](https://github.com/crystal-lang/crystal/issues/5237), thanks @MakeNowJust) - Give error instead of crashing when an unterminated string array literal (`%w()`) sits at the end of a file. ([#5241](https://github.com/crystal-lang/crystal/issues/5241), thanks @asterite) - Give error when attempting to use macro yield (`{{yield}}`) outside a macro. ([#5307](https://github.com/crystal-lang/crystal/issues/5307), thanks @MakeNowJust) - Fix error related to generic inheritance. ([#5284](https://github.com/crystal-lang/crystal/issues/5284), thanks @MakeNowJust) - Fix compiler crash when using recursive alias and generics. ([#5330](https://github.com/crystal-lang/crystal/issues/5330), thanks @MakeNowJust) - Fix parsing `foo(+1)` as `foo + 1` instead of `foo(1)` where `foo` was a local variable. ([#5336](https://github.com/crystal-lang/crystal/issues/5336), thanks @MakeNowJust) - Documentation generator: Keep quoted symbol literals quoted when syntax highlighting code blocks in documentation output. ([#5238](https://github.com/crystal-lang/crystal/issues/5238), thanks @MakeNowJust) - Documentation generator: Keep the original delimiter used when syntax highlighting string array literals. ([#5297](https://github.com/crystal-lang/crystal/issues/5297), thanks @MakeNowJust) - Documentation generator: Fix XSS vulnerability when syntax highlighting string array literals. ([#5259](https://github.com/crystal-lang/crystal/issues/5259), thanks @MakeNowJust) - Formatter: fix indentation of the last comment in a `begin`/`end` block. ([#5198](https://github.com/crystal-lang/crystal/issues/5198), thanks @MakeNowJust) - Formatter: fix formatting parentheses with multiple lines in. ([#5268](https://github.com/crystal-lang/crystal/issues/5268), thanks @MakeNowJust) - Formatter: fix formatting `$1?`. ([#5313](https://github.com/crystal-lang/crystal/issues/5313), thanks @MakeNowJust) - Formatter: ensure to insert a space between `{` and `%` characters to avoid forming `{%` macros. ([#5278](https://github.com/crystal-lang/crystal/issues/5278), thanks @MakeNowJust) ### Misc - Fix `Makefile`, CI, and gitignore to use the new documentation path after [#4937](https://github.com/crystal-lang/crystal/issues/4937). ([#5217](https://github.com/crystal-lang/crystal/issues/5217), thanks @straight-shoota) - Miscellaneous code cleanups. ([#5318](https://github.com/crystal-lang/crystal/issues/5318), [#5341](https://github.com/crystal-lang/crystal/issues/5341) and [#5366](https://github.com/crystal-lang/crystal/issues/5366), thanks @bew and @mig-hub) - Documentation fixes. ([#5253](https://github.com/crystal-lang/crystal/issues/5253), [#5296](https://github.com/crystal-lang/crystal/issues/5296), [#5300](https://github.com/crystal-lang/crystal/issues/5300) and [#5322](https://github.com/crystal-lang/crystal/issues/5322), thanks @arcage, @icyleaf, @straight-shoota and @bew) - Fix the in-repository changelog to include 0.24.0. ([#5331](https://github.com/crystal-lang/crystal/pull/5331), thanks @sdogruyol) ## 0.24.0 (2017-10-30) - **(breaking-change)** HTTP::Client#post_form is now HTTP::Client.post(form: ...) - **(breaking-change)** Array#reject!, Array#compact! and Array#select! now return self ([#5154](https://github.com/crystal-lang/crystal/pull/5154)) - **(breaking-change)** Remove the possibility to require big_int, big_float or big_rational individually: use require "big" instead ([#5121](https://github.com/crystal-lang/crystal/pull/5121)) - **(breaking-change)** Spec: remove expect_raises without type argument ([#5096](https://github.com/crystal-lang/crystal/pull/5096)) - **(breaking-change)** IO is now a class, no longer a module ([#4901](https://github.com/crystal-lang/crystal/pull/4901)) - **(breaking-change)** Time constructors now have nanosecond and kind as named argument ([#5072](https://github.com/crystal-lang/crystal/pull/5072)) - **(breaking-change)** Removed XML.escape. Use HTML.escape instead ([#5046](https://github.com/crystal-lang/crystal/pull/5046)) - **(breaking-change)** Removed macro def ([#5040](https://github.com/crystal-lang/crystal/pull/5040)) - **(breaking-change)** SecureRandom is now Random::Secure ([#4894](https://github.com/crystal-lang/crystal/pull/4894)) - **(breaking-change)** HTML.escape now only escapes &<>"' ([#5012](https://github.com/crystal-lang/crystal/pull/5012)) - **(breaking-change)** To define a custom hash method you must now define hash(hasher) ([#4946](https://github.com/crystal-lang/crystal/pull/4946)) - **(breaking-change)** Flate::Reader.new(&block) and Flate::Writer.new(&block) now use the name open ([#4887](https://github.com/crystal-lang/crystal/pull4887/)) - **(breaking-change)** Use an Enum for Process stdio redirections ([#4445](https://github.com/crystal-lang/crystal/pull/4445)) - **(breaking-change)** Remove '$0' special syntax - **(breaking-change)** Remove bare array creation from multi assign (a = 1, 2, 3) ([#4824](https://github.com/crystal-lang/crystal/pull/4824)) - **(breaking-change)** Rename skip macro method to skip_file ([#4709](https://github.com/crystal-lang/crystal/pull/4709)) - **(breaking-change)** StaticArray#map and Slice#map now return their same type instead of Array ([#5124](https://github.com/crystal-lang/crystal/pull/5124)) - **(breaking-change)** Tuple#map_with_index now returns a Tuple. ([#5086](https://github.com/crystal-lang/crystal/pull/5086)) - Packages built with LLVM 3.9.1. They should (hopefully) fix [#4719](https://github.com/crystal-lang/crystal/issues/4719) - Syntax: Allow flat rescue/ensure/else block in do/end block ([#5114](https://github.com/crystal-lang/crystal/pull/5114)) - Syntax: fun names and lib function calls can now start with Uppercase - Macros: Using an alias in macros will now automatically resolve it to is aliased type ([#4995](https://github.com/crystal-lang/crystal/pull/4995)) - Macros: The flags bits32 and bits64 are now automatically defined in macros - The YAML module has now full support for the 1.1 core schema with additional types, and properly supports aliases and merge keys ([#5007](https://github.com/crystal-lang/crystal/pull/5007)) - Add --output option to crystal docs ([#4937](https://github.com/crystal-lang/crystal/pull/4937)) - Add Time#days_in_year: it returns the no of days in a given year ([#5163](https://github.com/crystal-lang/crystal/pull/5163)) - Add Time.monotonic to return monotonic clock ([#5108](https://github.com/crystal-lang/crystal/pull/5108)) - Add remove_empty option to many String#split overloads - Add Math.sqrt overloads for Bigs ([#5113](https://github.com/crystal-lang/crystal/pull/5113)) - Add --stdin-filename to crystal command to compile source from STDIN ([#4571](https://github.com/crystal-lang/crystal/pull/4571)) - Add Crystal.main to more easily redefine the main of a program ([#4998](https://github.com/crystal-lang/crystal/pull/4998)) - Add Tuple.types that returns a tuple of types ([#4962](https://github.com/crystal-lang/crystal/pull/4962)) - Add NamedTuple.types that returns a named tuple of types ([#4962](https://github.com/crystal-lang/crystal/pull/4962)) - Add NamedTuple#merge(other : NamedTuple) ([#4688](https://github.com/crystal-lang/crystal/pull/4688)) - Add YAML and JSON.mapping presence: true option ([#4843](https://github.com/crystal-lang/crystal/pull/4843)) - Add Dir.each_child(&block) ([#4811](https://github.com/crystal-lang/crystal/pull/4811)) - Add Dir.children ([#4808](https://github.com/crystal-lang/crystal/pull/4808)) - HTML.unescape now supports all HTML5 named entities ([#5064](https://github.com/crystal-lang/crystal/pull/5064)) - Regex now supports duplicated named captures ([#5061](https://github.com/crystal-lang/crystal/pull/5061)) - rand(0) is now valid and returns 0 - Tuple#[] now supports a negative index ([#4735](https://github.com/crystal-lang/crystal/pull/4735)) - JSON::Builder#field now accepts non-scalar values ([#4706](https://github.com/crystal-lang/crystal/pull/4706)) - Number#inspect now shows the number type - Some additions to Big arithmetics ([#4653](https://github.com/crystal-lang/crystal/pull/4653)) - Increase the precision of Time and Time::Span to nanoseconds ([#5022](https://github.com/crystal-lang/crystal/pull/5022)) - Upgrade Unicode to 10.0.0 ([#5122](https://github.com/crystal-lang/crystal/pull/5122)) - Support LLVM 5.0 ([#4821](https://github.com/crystal-lang/crystal/pull/4821)) - [Lots of bugs fixed](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.24.0) ## 0.23.1 (2017-07-01) - Added `Random::PCG32` generator (See [#4536](https://github.com/crystal-lang/crystal/issues/4536), thanks @konovod) - WebSocket should compare "Upgrade" header value with case insensitive (See [#4617](https://github.com/crystal-lang/crystal/issues/4617), thanks @MakeNowJust) - Fixed macro lookup from included module (See [#4639](https://github.com/crystal-lang/crystal/issues/4639), thanks @asterite) - Explained "crystal tool expand" in crystal(1) man page (See [#4643](https://github.com/crystal-lang/crystal/issues/4643), thanks @MakeNowJust) - Explained how to detect end of file in `IO` (See [#4661](https://github.com/crystal-lang/crystal/issues/4661), thanks @oprypin) ## 0.23.0 (2017-06-27) - **(breaking-change)** `Logger#formatter` takes a `Severity` instead of a `String` (See [#4355](https://github.com/crystal-lang/crystal/issues/4355), [#4369](https://github.com/crystal-lang/crystal/issues/4369), thanks @Sija) - **(breaking-change)** Removed `IO.select` (See [#4392](https://github.com/crystal-lang/crystal/issues/4392), thanks @RX14) - Added `Crystal::System::Random` namespace (See [#4450](https://github.com/crystal-lang/crystal/issues/4450), thanks @ysbaddaden) - Added `Path#resolve?` macro method (See [#4370](https://github.com/crystal-lang/crystal/issues/4370), [#4408](https://github.com/crystal-lang/crystal/issues/4408), thanks @RX14) - Added range methods to `BitArray` (See [#4397](https://github.com/crystal-lang/crystal/issues/4397), [#3968](https://github.com/crystal-lang/crystal/issues/3968), thanks @RX14) - Added some well-known HTTP Status messages (See [#4419](https://github.com/crystal-lang/crystal/issues/4419), thanks @akzhan) - Added compiler progress indicator (See [#4182](https://github.com/crystal-lang/crystal/issues/4182), thanks @RX14) - Added `System.cpu_cores` (See [#4449](https://github.com/crystal-lang/crystal/issues/4449), [#4226](https://github.com/crystal-lang/crystal/issues/4226), thanks @miketheman) - Added `separator` and `quote_char` to `CSV#each_row` (See [#4448](https://github.com/crystal-lang/crystal/issues/4448), thanks @timsu) - Added `map_with_index!` to `Pointer`, `Array` and `StaticArray` (See [#4456](https://github.com/crystal-lang/crystal/issues/4456), [#3356](https://github.com/crystal-lang/crystal/issues/3356), [#3354](https://github.com/crystal-lang/crystal/issues/3354), thanks @Nephos) - Added `headers` parameter to `HTTP::WebSocket` constructors (See [#4227](https://github.com/crystal-lang/crystal/issues/4227), [#4222](https://github.com/crystal-lang/crystal/issues/4222), thanks @adamtrilling) - Added `unlink` to `XML::Node` (See [#4515](https://github.com/crystal-lang/crystal/issues/4515), [#4331](https://github.com/crystal-lang/crystal/issues/4331), thanks @RX14 and @MrSorcus) - Added `Math.frexp` (See [#4560](https://github.com/crystal-lang/crystal/issues/4560), thanks @akzhan) - Added `Regex::MatchData` support for negative indexes (See [#4566](https://github.com/crystal-lang/crystal/issues/4566), thanks @MakeNowJust) - Added `captures`, `named_captures`, `to_a` and `to_h` to `Regex::MatchData` (See [#3783](https://github.com/crystal-lang/crystal/issues/3783), thanks @MakeNowJust) - Added `|` as a string delimiter to allow `q|string|` syntax (See [#3467](https://github.com/crystal-lang/crystal/issues/3467), thanks @RX14) - Added support for Windows linker (See [#4491](https://github.com/crystal-lang/crystal/issues/4491), thanks @RX14) - Added llvm operand bundle def and catch pad/ret/switch in order to support Windows SEH (See [#4501](https://github.com/crystal-lang/crystal/issues/4501), thanks @bcardiff) - Added `Float::Printer` based on Grisu3 to speed up float to string conversion (See [#4333](https://github.com/crystal-lang/crystal/issues/4333), thanks @will) - Added `Object.unsafe_as` to unsafely reinterpret the bytes of an object as being of another `type` (See [#4333](https://github.com/crystal-lang/crystal/issues/4333), thanks @asterite) - Added `.downcase(Unicode::CaseOptions::Fold)` option which convert strings to casefolded strings for caseless matching (See [#4512](https://github.com/crystal-lang/crystal/issues/4512), thanks @akzhan) - Added `OpenSSL::DigestIO` to wrap an IO while calculating a digest (See [#4260](https://github.com/crystal-lang/crystal/issues/4260), thanks @spalladino) - Added `zero?` to numbers and time spans (See [#4026](https://github.com/crystal-lang/crystal/issues/4026), thanks @jellymann) - Added `TypeNode#has_method?` method (See [#4474](https://github.com/crystal-lang/crystal/issues/4474), thanks @Sija) - `Regex::MatchData#size` renamed to `#group_size` (See [#4565](https://github.com/crystal-lang/crystal/issues/4565), thanks @MakeNowJust) - `HTTP::StaticFileHandler` can disable directory listing (See [#4403](https://github.com/crystal-lang/crystal/issues/4403), [#4398](https://github.com/crystal-lang/crystal/issues/4398), thanks @joaodiogocosta) - `bin/crystal` now uses `/bin/sh` instead of `/bin/bash` (See [#3809](https://github.com/crystal-lang/crystal/issues/3809), [#4410](https://github.com/crystal-lang/crystal/issues/4410), thanks @TheLonelyGhost) - `crystal init` generates a `.editorconfig` file (See [#4422](https://github.com/crystal-lang/crystal/issues/4422), [#297](https://github.com/crystal-lang/crystal/issues/297), thanks @akzhan) - `man` page for `crystal` command (See [#2989](https://github.com/crystal-lang/crystal/issues/2989), [#1291](https://github.com/crystal-lang/crystal/issues/1291), thanks @dread-uo) - Re-raising an exception doesn't overwrite its callstack (See [#4487](https://github.com/crystal-lang/crystal/issues/4487), [#4482](https://github.com/crystal-lang/crystal/issues/4482), thanks @akzhan) - MD5 and SHA1 documentation clearly states they are not cryptographically secure anymore (See [#4426](https://github.com/crystal-lang/crystal/issues/4426), thanks @RX14) - Documentation about constructor methods now rendered separately (See [#4216](https://github.com/crystal-lang/crystal/issues/4216), thanks @Sija) - Turn `Random::System` into a module (See [#4542](https://github.com/crystal-lang/crystal/issues/4542), thanks @oprypin) - `Regex::MatchData` pretty printed (See [#4574](https://github.com/crystal-lang/crystal/issues/4574), thanks @MakeNowJust) - `String.underscore` treats digits as downcase or upcase characters depending previous characters (See [#4280](https://github.com/crystal-lang/crystal/issues/4280), thanks @MakeNowJust) - Refactor time platform specific implementation (See [#4502](https://github.com/crystal-lang/crystal/issues/4502), thanks @bcardiff) - Fixed Crystal not reusing .o files across builds (See [#4336](https://github.com/crystal-lang/crystal/issues/4336)) - Fixed `SomeClass.class.is_a?(SomeConst)` causing an "already had enclosing call" exception (See [#4364](https://github.com/crystal-lang/crystal/issues/4364), [#4390](https://github.com/crystal-lang/crystal/issues/4390), thanks @rockwyc992) - Fixed `HTTP::Params.parse` query string with two `=` gave wrong result (See [#4388](https://github.com/crystal-lang/crystal/issues/4388), [#4389](https://github.com/crystal-lang/crystal/issues/4389), thanks @akiicat) - Fixed `Class.class.is_a?(Class.class.class.class.class)` 🎉 (See [#4375](https://github.com/crystal-lang/crystal/issues/4375), [#4374](https://github.com/crystal-lang/crystal/issues/4374), thanks @rockwyc992) - Fixed select hanging when sending before receive (See [#3862](https://github.com/crystal-lang/crystal/issues/3862), [#3899](https://github.com/crystal-lang/crystal/issues/3899), thanks @kostya) - Fixed "Unknown key in access token json: id_token" error in OAuth2 client (See [#4437](https://github.com/crystal-lang/crystal/issues/4437)) - Fixed macro lookup conflicting with method lookup when including on top level (See [#236](https://github.com/crystal-lang/crystal/issues/236)) - Fixed Vagrant images (See [#4510](https://github.com/crystal-lang/crystal/issues/4510), [#4508](https://github.com/crystal-lang/crystal/issues/4508), thanks @Val) - Fixed `IO::FileDescriptor#seek` from current position (See [#4558](https://github.com/crystal-lang/crystal/issues/4558), thanks @ysbaddaden) - Fixed `IO::Memory#gets_to_end` to consume the `IO` (See [#4415](https://github.com/crystal-lang/crystal/issues/4415), thanks @jhass) - Fixed setting of XML attributes (See [#4562](https://github.com/crystal-lang/crystal/issues/4562), thanks @asterite) - Fixed "SSL_shutdown: Operation now in progress" error by retrying (See [#3168](https://github.com/crystal-lang/crystal/issues/3168), thanks @akzhan) - Fixed WebSocket negotiation (See [#4386](https://github.com/crystal-lang/crystal/issues/4386), thanks @RX14) ## 0.22.0 (2017-04-20) - **(breaking-change)** Removed `Process.new(pid)` is now private (See [#4197](https://github.com/crystal-lang/crystal/issues/4197)) - **(breaking-change)** IO#peek now returns an empty slice on EOF (See [#4240](https://github.com/crystal-lang/crystal/issues/4240), [#4261](https://github.com/crystal-lang/crystal/issues/4261)) - **(breaking-change)** Rename `WeakRef#target` to `WeakRef#value` (See [#4293](https://github.com/crystal-lang/crystal/issues/4293)) - **(breaking-change)** Rename `HTTP::Params.from_hash` to `HTTP::Params.encode` (See [#4205](https://github.com/crystal-lang/crystal/issues/4205)) - **(breaking-change)** `'\"'` is now invalid, use `'"'` (See [#4309](https://github.com/crystal-lang/crystal/issues/4309)) - Improved backtrace function names are now read from DWARF sections (See [#3958](https://github.com/crystal-lang/crystal/issues/3958), thanks @ysbaddaden) - Improved sigfaults and exceptions are printed to STDERR (See [#4163](https://github.com/crystal-lang/crystal/issues/4163), thanks @Sija) - Improved SSL Sockets are now buffered (See [#4248](https://github.com/crystal-lang/crystal/issues/4248)) - Improved type inference on loops (See [#4242](https://github.com/crystal-lang/crystal/issues/4242), [#4243](https://github.com/crystal-lang/crystal/issues/4243)) - Improved `pp` and `p`, the printed value is returned (See [#4285](https://github.com/crystal-lang/crystal/issues/4285), [#4283](https://github.com/crystal-lang/crystal/issues/4283), thanks @MakeNowJust) - Added support for OpenSSL 1.1.0 (See [#4215](https://github.com/crystal-lang/crystal/issues/4215), [#4230](https://github.com/crystal-lang/crystal/issues/4230), thanks @ysbaddaden) - Added `SecureRandom#random_bytes(Bytes)` (See [#4191](https://github.com/crystal-lang/crystal/issues/4191), thanks @konovod) - Added setting and deleting of attributes on `XML::Node` (See [#3902](https://github.com/crystal-lang/crystal/issues/3902), thanks @bmmcginty) - Added `File.touch` and `FileUtils.touch` methods (See [#4069](https://github.com/crystal-lang/crystal/issues/4069), thanks @Sija) - Added `#values_at` for `CSV` (See [#4157](https://github.com/crystal-lang/crystal/issues/4157), thanks @need47) - Added `Time#clone` (See [#4174](https://github.com/crystal-lang/crystal/issues/4174), thanks @Sija) - Added `ancestors` macro method (See [#3875](https://github.com/crystal-lang/crystal/issues/3875), thanks @david50407) - Added `skip` macro method ([#4237](https://github.com/crystal-lang/crystal/issues/4237), thanks @mverzilli) - Added `Colorize.on_tty_only!` for easier toggling (See [#4075](https://github.com/crystal-lang/crystal/issues/4075), [#4271](https://github.com/crystal-lang/crystal/issues/4271), thanks @MakeNowJust) - Added `WebSocket#on_binary` to receive binary messages (See [#2774](https://github.com/crystal-lang/crystal/issues/2774), thanks @lbguilherme) - Fixed `Iterator.of` stops iterating when `Iterator.stop` is returned (See [#4208](https://github.com/crystal-lang/crystal/issues/4208)) - Fixed `String#insert` for non-ascii Char (See [#4164](https://github.com/crystal-lang/crystal/issues/4164), thanks @Papierkorb) - Fixed `File.link` now creates a hard link ([#4116](https://github.com/crystal-lang/crystal/issues/4116), thanks @KCreate) - Fixed error message for `#to_h` over empty `NamedTuple` (See [#4076](https://github.com/crystal-lang/crystal/issues/4076), thanks @karlseguin) - Fixed `NamedTuple#to_h` does no longer call to value's `#clone` (See [#4203](https://github.com/crystal-lang/crystal/issues/4203)) - Fixed `Math#gamma` and `Math#lgamma` (See [#4229](https://github.com/crystal-lang/crystal/issues/4229), thanks @KCreate) - Fixed `TCPSocket` creation for 0 port for Mac OSX (See [#4177](https://github.com/crystal-lang/crystal/issues/4177), thanks @will) - Fixed repo name extraction from git remote in doc tool (See [#4132](https://github.com/crystal-lang/crystal/issues/4132), thanks @Sija) - Fixed `self` resolution when including a generic module (See [#3972](https://github.com/crystal-lang/crystal/issues/3972), thanks @MakeNowJust) - Fixed debug information was missing in some cases (See [#4166](https://github.com/crystal-lang/crystal/issues/4166), [#4202](https://github.com/crystal-lang/crystal/issues/4202), [#4254](https://github.com/crystal-lang/crystal/issues/4254)) - Fixed use generic ARM architecture target triple for all ARM architectures (See [#4167](https://github.com/crystal-lang/crystal/issues/4167), thanks @ysbaddaden) - Fixed macro run arguments escaping - Fixed zsh completion (See [#4284](https://github.com/crystal-lang/crystal/issues/4284), thanks @veelenga) - Fixed honor `--no-color` option in spec (See [#4306](https://github.com/crystal-lang/crystal/issues/4306), thanks @luislavena) - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.22.0) ## 0.21.1 (2017-03-06) - Improved lookup of abstract def implementors (see [#4052](https://github.com/crystal-lang/crystal/issues/4052)) - Improved allocation of objects without pointer instance variables using `malloc_atomic` (see [#4081](https://github.com/crystal-lang/crystal/issues/4081)) - Added `crystal --version` reports also the LLVM version (see [#4095](https://github.com/crystal-lang/crystal/issues/4095), thanks @matiasgarciaisaia) - Fixed instance variables initializers corner cases (see [#3988](https://github.com/crystal-lang/crystal/issues/3988)) - Fixed `crystal play` was broken (see [#4061](https://github.com/crystal-lang/crystal/issues/4061)) - Fixed `Atomic` can be set to `nil` (see [#4062](https://github.com/crystal-lang/crystal/issues/4062)) - Fixed `GZip::Header` extra byte (see [#4068](https://github.com/crystal-lang/crystal/issues/4068), thanks @crisward) - Fixed `ASTNode#to_s` for `Attribute` (see [#4098](https://github.com/crystal-lang/crystal/issues/4098), thanks @olbat) - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.21.1) ## 0.21.0 (2017-02-20) - **(breaking-change)** The compiler now reuses previous macro run compilations so `{{ run(...) }}` is only re-run if the code changes - **(breaking-change)** Spec: `assert { ... }` is now `it { ... }` (thanks @TheLonelyGhost) - **(breaking-change)** Renamed `Set#merge!` to `Set#concat` - **(breaking-change)** `Zlib` was split into `Flate`, `Gzip` and `Zlib` ([bda40f](https://github.com/crystal-lang/crystal/commit/bda40f)) - **(breaking-change)** `Crypto::MD5` is now `Digest::MD5` - **(breaking-change)** `String#chop` is now `String#rchop` - **(breaking-change)** `String#to_slice` now returns a read-only Slice - **(breaking-change)** `String` can now hold invalid UTF-8 byte sequences, and they produce a unicode replacement character when traversed - **(breaking-change)** Removed `String#lchomp`. Use `String#lchop` - **(breaking-change)** Octal escapes inside strings incorrectly produced a codepoint value instead of a byte value - **(breaking-change)** Removed octal escape from char literals - Fixed compiler performance regression related to cached files ([f69e37e](https://github.com/crystal-lang/crystal/commit/f69e37e)) - Added `\xHH` escape sequence in string literals - `Char::Reader` can now traverse a string backwards - `Enum#to_s` now uses pipes instead of commas for flag enums - `IO#read_string` is now encoding-aware - `OAuth2::Client` now sends `application/json` Accept header, and considers the `expires_in` access token property as optional - `Slice` can now be read-only - `TCPServer` no longer set SO_REUSEPORT to true by default - Added `HTTP::Multipart` and `HTTP::FormData` (thanks @RX14) - Added `File::Stat#pipe?` - Added `File.utime` - Added `IO#peek` - Added `String#strip(arg)`, `String#lstrip(arg)`, `String#rstrip(arg)` - Added `String#lchop`, `String#lchop(prefix)`, `String#rchop` and `String#rchop(suffix)` - Added `String#hexbytes` and `String#hexbytes?` - Added `String#scrub` and `String#valid_encoding?` - Added `include?` macro method for StringLiteral, SymbolLiteral and MacroId (thanks @karlseguin) - Added "view source" links to GitLab (thanks @ezrast) - Updated CONTRIBUTING.md guidelines - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.21.0) ## 0.20.5 (2017-01-20) - Improved performance in `String#index`, `String#rindex` due to Rabin-Karp algorithm (thanks @MakeNowJust). - Improved performance in `Crypto::Bcrypt` (see [#3880](https://github.com/crystal-lang/crystal/issues/3880), thanks @ysbaddaden). - `expect_raises` returns raised exception (thanks @kostya). - Line numbers debug information is always generated (see [#3831](https://github.com/crystal-lang/crystal/issues/3831), thanks @ysbaddaden). - Added `Zip::File`, `Zip::Reader` and `Zip::Writer`. Native readers for zip files that delegate compression to existing zlib module. - Added `Hash#delete` with block (see [#3856](https://github.com/crystal-lang/crystal/issues/3856), thanks @bmulvihill). - Added `String#[](char : Char)` (see [#3855](https://github.com/crystal-lang/crystal/issues/3855), thanks @Sija). - Added `crystal tool expand` to expand macro call in a given location (see [#3732](https://github.com/crystal-lang/crystal/issues/3732), thanks @MakeNowJust). - Fixed `crystal play` is able to show compilation errors again. - `crystal doc` recognizes `crystal-lang/crystal` in any remote (thanks @MaxLap). - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.20.5) ## 0.20.4 (2017-01-06) - **(breaking change)** A type that wants to convert itself to JSON now must override `to_json(builder : JSON::Builder)` instead of `to_json(io : IO)`. The same is true for custom JSON converters. If you are using `JSON.mapping` then your code will continue to work without changes. - **(breaking change)** Defining a `finalize` method on a struct now gives a compile error - **(breaking change)** Default argument types now must match their restriction, if any (for example `def foo(x : Int32 = nil)` will now fail to compile if `foo` is invoked without arguments) (thanks @MakeNowJust) - **(breaking change)** `each` methods now return `Nil` - **(breaking change)** `IO#skip(bytes)` will now raise if there aren't at least the given amount of bytes in the `IO` (previously it would work well if there were less bytes, and it would hang if there were more) - **(breaking change)** `MemoryIO` was removed (use `IO::Memory` instead) - **(breaking change)** `Number#step` now requires named arguments, `to` and `by`, to avoid argument order confusion - **(breaking change)** `YAML::Emitter` was renamed to `YAML::Builder`, and some of its methods were also renamed - **(breaking change)** `XML::Node#[]` now always returns a `String` (previously it could also return `Nil`, which was incorrect) - **(breaking change)** `XML::Node#content` now returns an empty `String` when no content is available - `HTTP::Client` now automatically reconnects on a dropped keep-alive connection - `with ... yield` now works well with `method_missing` - Class variables can now be used in generic types (all generic instances share the same variable, and subclasses get their own copy, as usual) - Added support for LLVM 4 (thanks @ysbaddaden) - Added `Enum.each` and `Enum#each` (thanks @ysbaddaden) - Added `Hash#compact` and `Hash#compact!` (thanks @MakeNowJust) - Added `IO#read_string(bytesize)` - Added `IO#skip_to_end` - Added `Iterator#flat_map` (thanks @MakeNowJust) - Added `JSON.build` and `JSON::Builder` - Added `NamedTuple#has_key?(String)` (thanks @Sija) - Added `p(NamedTuple)` (thanks @splattael) - Added `Regex::MatchData#==` (thanks @MakeNowJust) - Added `String#sub(Regex, NamedTuple)` (thanks @maiha) - Added `XML.build` and `XML::Builder` - Lots of improvements and applied consistencies to doc comments (thanks @Sija and @maiha) - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.20.4) ### 0.20.3 (2016-12-23) - **(breaking change)** `IO#gets`, `IO#each_line`, `String#lines`, `String#each_line`, etc. now chomp lines by default. You can pass `chomp: false` to prevent automatic chomping. Note that `chomp` is `true` by default for argless `IO#gets` (read line) but `false` if args are given. - **(breaking change)** `HTTP::Handler` is now a module instead of a class (thanks @andrewhamon) - **(breaking change)** Free variables now must be specified with `forall`, a single uppercase letter will not work anymore - **(breaking change)** The `libs` directory is no longer in the default CRYSTAL_PATH, use `lib` (running `crystal deps` should fix this) - Optimized compile times, specially on linux - `private` can now be used with macros inside types (thanks @MakeNowJust) - CLI: the `-s`/`--stats` option now also shows execution time (thanks @MakeNowJust) - CLI: added `-t`/`--time` to show execution time (thanks @MakeNowJust) - `Socket` now allows any family/type/protocol association, [and many other improvements](https://github.com/crystal-lang/crystal/pull/3750) (thanks @ysbaddaden) - YAML: an `IO` can now be passed to `from_yaml` (thanks @MakeNowJust) - Added `class_getter`, `class_setter`, `class_property`, etc. (thanks @Sija) - Added `String#lchomp` (thanks @Sija) - Added `IO#read_fully?` - Added `Iterator#flatten` (thanks @MakeNowJust) - Added `HTTP::WebSocket#ping`, `pong`, `on_ping`, `on_pong`, and now a ping message is automatically replied with a pong message (thanks @Sija) - Added `File#empty?` and `Dir#empty?` (thanks @dylandrop) - Added `Time::Span#/(Time::Span)` (thanks @RX14) - Added `String#split` versions that accept a block (thanks @splattael) - Added `URI#normalize` and `normalize!` (thanks @taylorfinnell) - Added `reuse` optional argument to many `Array`, `Enumerable` and `Iterable` methods that allow you to reuse the yielded/return array for better performance and less memory footprint - The `:debug` flag is now present when compiled with `--debug`, useful for doing `flag?(:debug)` in macros (thanks @luislavena) - [Many bug fixes and performance improvements](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.20.3) ### 0.20.1 (2016-12-05) - **(breaking change)** `Set#merge` as renamed to `Set#merge!` - **(breaking change)** `Slice.new(size)` no longer works with non primitive integers and floats - **(breaking change)** The macro method `argify` was renamed to `splat` - Added pretty printing. The methods `p` and `pp` now use it. To get the old behaviour use `puts obj.inspect` - Added `ArrayLiteral#[]=`, `TypeNode#constant`, `TypeNode#overrides?` and `HashLiteral#double_splat` in macros - Added a `finished` macro hook that runs at the end of the program - Added support for declaring the type of a local variable - Added `Slice.empty` - Flags enums now have a `none?` method - `IO::ByteFormat` has now methods to encode/decode to/from a `Slice` - Spec: the line number passed to run a specific `it` block can now be inside any line of that block - The `CallConvention` attribute can now also be applied to a `lib` declaration, and all `fun`s inside it will inherit it - The `method_missing` hook can now define a method, useful for specifying block arguments - Support double splat in macros (`{{**...}}`) - [Some bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.20.1) ### 0.20.0 (2016-11-22) - **(breaking change)** Removed `ifdef` from the language - **(breaking change)** Removed `PointerIO` - **(breaking change)** The `body` property of `HTTP::Request` is now an `IO?` (previously it was `String`). Use `request.body.try(&.gets_to_end)` if you need the entire body as a String. - **(breaking change)** `MemoryIO` has been renamed to `IO::Memory`. The old name can still be used but will produce a compile-time warning. `MemoryIO` will be removed immediately after 0.20.0. - **(breaking change)** `Char#digit?` was split into `Char#ascii_number?` and `Char#number?`. The old name is still available and will produce a compile-time warning, but will be removed immediately after 0.20.0. - **(breaking change)** `Char#alpha?` was split into `Char#ascii_letter?` and `Char#letter?`. The old name is still available and will produce a compile-time warning, but will be removed immediately after 0.20.0. - **(breaking change)** The `Iterable` module is now generic - Many `String` and `Char` methods are now unicode-aware, for example `String#downcase`, `String#upcase`, `Char#downcase`, `Char#upcase`, `Char#whitespace?`, etc. - Added support for HTTP client and server streaming. - Added support for ARM (thanks @ysbaddaden) - Added support for AArch64 (thanks @ysbaddaden) - Added support for LLVM 3.9 (thanks @ysbaddaden) - Added `__END_LINE__` magic constant in method default arguments: will be the last line of a call (if the call has a block, it will be the last line of that block) - Added `@def` inside macros that takes the value of the current method - API docs have a nicer style now, and notes like TODO and DEPRECATED are better highlighted (thanks @samueleaton) - Slight improvement to debugging support (thanks @ggiraldez) - Line numbers in backtraces (linux only for now) (thanks @ysbaddaden) - Added iteration times to `Benchmark.ips` (thanks @RX14) - Allow `HTTP::Client` block initializer to be used when passing an URI (thanks @philnash) - `JSON.mapping` and `YAML.mapping` getter/setter generation can now be controlled (thanks @zatherz) - `Time` is now serializable to JSON and YAML using ISO 8601 date-time format - Added `IO::MultiWriter` (thanks @RX14) - Added `String#index(Regex)` and `String#rindex(Regex)` (thanks @zatherz) - Added `String#partition` and `String#rpartition` (thanks @johnjansen) - Added `FileUtils.cd`, `FileUtils.mkdir`, `FileUtils.mkdir_p`, `FileUtils.mv`, `FileUtils.pwd`, `FileUtils.rm`, `FileUtils.rm_r`, `FileUtils.rmdir` (thanks @ghivert) - Added `JSON::Builder#raw_field` (thanks @kostya) - Added `Enumerable#chunks` and `Iterator#chunk` (thanks @kostya) - Added `Iterator#with_index` - Several enhancements to the Random module: now works for any integer type and avoids overflows (thanks @BlaXpirit) - Optimized `Array#sort` by using introsort (thanks @c910335) - [Several bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.20.0) ### 0.19.4 (2016-10-07) - Added support for OpenBSD (thanks @wmoxam and @ysbaddaden) - More iconv fixes for FreeBSD (thanks @ysbaddaden) - Changed how `require` works for the upcoming `shards` release (this is backwards compatible). See https://github.com/crystal-lang/crystal/pull/2788 - Added `Atomic` and exposed all LLVM atomic instructions to Crystal (needed to implemented multiple-thread support) - Added `Process.executable_path` (thanks @kostya, @whereami and @ysbaddaden) - Added `HTML.unescape` (thanks @dukex) - Added `Char#+(Int)` and `Char#-(Int)` - [A few bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.19.4) ### 0.19.3 (2016-09-30) - `crystal eval` now accepts some flags like `--stats`, `--release` and `--help` - Added `File.chown` and `File.chmod` (thanks @ysbaddaden) - Added `Time::Span.zero` (useful for doing `sum`) (thanks @RX14) - Added docs to `OAuth` and `OAuth2` - [Several bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.19.3) ### 0.19.2 (2016-09-16) - Generic type variables no longer need to be single-letter names (for example `class Gen(Foo)` is now possible) - Added syntax to denote free variables: `def foo(x : T) forall T`. The old rule of single-letter name still applies but will be removed in the future. - Removed the restriction that top-level types and constants can't have single-letter names - Added `@[Extern]` attribute to mark regular Crystal structs as being able to be used in C bindings - Faster `Char#to_s` when it's ASCII: this improves the performance of JSON and CSV parsing - `crystal spec`: allow passing `--release` and other options - `crystal spec`: allow running all specs in a given directory - `crystal playground`: support custom workbook resources (thanks @bcardiff) - `crystal playground`: standard output now understands ANSI colors (thanks @bcardiff) - Added many more macro methods to traverse AST nodes (thanks @BlaXpirit) - Error messages no longer include a type trace by default, pass `--error-trace` to show the full trace (the trace is often useless and makes it harder to understand error messages) - [Several bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.19.2) ### 0.19.1 (2016-09-09) - Types (class, module, etc.) can now be marked as `private`. - Added `WeakRef` (thanks @bcardiff) - [Several bug fixes](https://github.com/crystal-lang/crystal/issues?q=is%3Aclosed+milestone%3A0.19.1) ### 0.19.0 (2016-09-02) - **(breaking change)** Added `select` keyword - **(breaking change)** Removed $global variables. Use @@class variables instead. - **(breaking change)** Heredoc now ends when the matching identifier is found, either followed by a space or by a non-identifier - **(breaking change)** Assignment to a local variable inside an assignment to that same variable is now an error - **(breaking change)** Type names like `T`, `T1`, `U`, etc., are now disallowed at the top level, to avoid conflicts with free variables - **(breaking change)** Type lookup (`Foo::Bar::Baz`) had some incorrect behaviour that now is fixed. This can break existing code that relied on this incorrect behaviour. The fix is to fully qualify types (`::Foo::Bar::Baz`) - **(breaking change)** In relationships like `class Bar < Foo(Baz)` and `include Moo(Baz)`, all of `Foo`, `Moo` and `Baz` must be defined before that point (this was not always the case in previous versions) - **(breaking change)** Removed the deprecated syntax `x as T` - **(breaking change)** Removed block form of `String#match` - **(breaking change)** Removed `IO#read_nonblock` - **(breaking change)** `Int#/` now performs floored division. Use `Int#tdiv` for truncated division (see their docs to learn the difference) - Added support for LLVM 3.8 (thanks @omarroth) - `||` now does type filtering - Generic inheritance should now work well, and (instantiated) generic modules can now be used as the type of instance variables - `NamedTuple` can now be accessed with strings too (thanks @jhass) - `Base64` can now encode and decode directly to an `IO` (thanks @kostya) - `BigInt` now uses GMP implementation of gcd and lcm (thanks @endSly) - `ECR` now supports removing leading and trailing whitespace (`<%-`, `-%>`) - `HTTP::Request#path` now never returns `nil`: it fallbacks to `"/"` (thanks @jhass) - `String#tr(..., "")` is now the same as `String#delete` - `tool hierarchy` now supports `--format json` (thanks @bmulvihill) - Added `Char#ascii?` - Added `Class#nilable?` and `Union#nilable?` - Added `Hash#has_value?` (thanks @kachick) - Added `IO::Sized` and `IO::Delimited` (thanks @RX14) - Added `IO::Hexdump` (thanks @ysbaddaden) - Added `IO#noecho` and `IO#noecho!` (thanks @jhass) - Added `Logger.new(nil)` to create a null logger - Added `OptionParser#missing_option` and `OptionParser#invalid_option` (thanks @jhass) - Added `Process.exists?`, `Process#exists?` and `Process#terminated?` (thanks @jhass) - Added `Process.exec` (thanks @jhass) - Added `Slice#copy_to`, `Slice#copy_from`, `Slice#move_to` and `Slice#move_from` (thanks @RX14) - Added `URI#==` and `URI#hash` (thanks @timcraft) - Added `YAML#parse(IO)` - Added `Indexable` module that `Array`, `Slice`, `Tuple` and `StaticArray` include - Added `indent` parameter to `to_pretty_json` - Added lazy form of `getter` and `property` macros - Added macro methods to access an ASTNode's location - Unified String and Char to integer/float conversion API (thanks @jhass) - [Lots of bug fixes](https://github.com/crystal-lang/crystal/milestone/5?closed=1) ### 0.18.7 (2016-07-03) - The `compile` command was renamed back to `build`. The `compile` command is deprecated and will be removed in a future version - Fibers now can be spawned with a name - ECR macros can now be required with just `require "ecr"` - [Several bugs fixes and enhancements](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.18.7+is%3Aclosed) ### 0.18.6 (2016-06-28) - `T?` is now parsed as `Union(T, Nil)` outside the type grammar - Added `String#sub` overloads for replacing an index or range with a char or string - [Several bugs fixes](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.18.6+is%3Aclosed) ### 0.18.5 (2016-06-27) - Added `OpenSSL::SSL::Socket#alpn_protocol` - Added `IO#copy(src, desc, limit)` (thanks @jreinert) - Added `TypeNode#instance` macro method - [Several bugs fixes](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.18.5+is%3Aclosed) ### 0.18.4 (2016-06-21) - Fixed [#2887](https://github.com/crystal-lang/crystal/issues/2887) - Fix broken specs ### 0.18.3 (2016-06-21) - `TypeNode`: added `<`, `<=`, `>` and `>=` macro methods - [Several bugs fixes](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.18.3+is%3Aclosed) ### 0.18.2 (2016-06-16) - Fixed building Crystal from the source tarball ### 0.18.1 (2016-06-16) - Spec: passing `--profile` shows the slowest 10 specs (thanks @mperham) - Added `StringLiteral#>` and `StringLiteral#<` in macros - [Several bugs fixes](https://github.com/crystal-lang/crystal/issues?q=milestone%3A0.18.1+is%3Aclosed) ### 0.18.0 (2016-06-14) - **(breaking change)** `IniFile` was renamed to `INI`, and its method `load` renamed to `parse` - **(breaking change)** `Process.getpgid` was renamed to `Process.pgid` - **(breaking change)** An `Exception`'s backtrace is now set when it's raised, not when it's created: it's `backtrace` method raises if it's not set, and there's `backtrace?` to get it as a nilable array - **(breaking change)** `dup` is now correctly implemented in all types. `clone` is not defined by default, but some types in the standard library do. Also check `Object#def_clone` - **(breaking change)** the `method_missing` macro only accepts a single argument: a `Call` now. The form that accepted 3 arguments was removed. - **(breaking change)** the `delegate` macro must now be used like `delegate method1, method2, ..., methodN, to: object` - **(breaking change)** `Hash#each_with_index` and `Hash#each_with_object` now yield a tuple (pair) and an index, because `Hash` is now `Enumerable`. Use `do |(key, value), index|` for this. - **(breaking change)** `{"foo": 1}` denotes a named tuple literal now, not a hash literal. Use `{"foo" => 1}` instead. This also applies to, for example `HTTP::Headers{...}` - **(breaking change)** Extra block arguments now give a compile-time error. This means that methods that yield more than once, one time with N arguments and another time with M arguments, with N < M, will always give an error. To fix this, add M - N `nil` fillers on the yield side (this makes it more explicit that `nil` was intended to be a block argument value) - **(breaking change)** `OpenSSL::SSL::Context` and `OpenSSL::SSL::Socket` can no longer be used directly anymore. Use their respective subclasses `OpenSSL::SSL::Context::Client`, with `OpenSSL::SSL::Socket::Client`, `OpenSSL::SSL::Context::Server` with `OpenSSL::SSL::Socket::Server`. - **(breaking change)** TLS server and client sockets now use sane defaults, including support for hostname verification for client sockets, used by default in `HTTP::Client`. - **(breaking change)** The `ssl` option was renamed to `tls` in `HTTP::Client`, `HTTP::Server`, `HTTP::WebSocket`, `OAuth::Consumer`, `OAuth::Signature` and `OAuth2::AccessToken`. - The `dns_timeout` setting in a few classes like `HTTP::Client` and `TCPSocket` is now ignored until a next version supports a non-blocking `getaddrinfo` equivalent - `OpenSSL::SSL::Socket::Client` supports server name indication now. - The `build` command was renamed to `compile`. The `build` command is deprecated and will be removed in a future version - The `--cross-compile` flag no longer takes arguments, use `--target` and `-D` - Added a `Union` type that represents the type of a union, which can have class methods - Methods, procs and lib functions that are marked as returning `Void` now return `Nil` - Methods that are marked as returning `Nil` are not checked for a correct return type, they always return `nil` now - When `as` fails at runtime it now includes which type couldn't be cast - Macros can now be used inside `lib` and `enum` declarations - Macros can now be declared inside enums - Macro calls can now be used as enum values - Generic types can now include a splatted type variable. This already existed in the language (`Tuple(*T)`, `Proc(*T)`) but there was no syntax to define such types. - Class variables are now inherited (only their type, not their value). They are now similar to Ruby class instance variables. - Splats in `yield` can now be used - Splat in block arguments can now be used. - Added block auto-unpacking: if a method yields a tuple and a block specifies more then one block argument, the tuple is unpacked to these arguments - String literals are now allowed as external method arguments, to match named tuples and named arguments - `sizeof` and `instance_sizeof` can now be used as generic type arguments (mostly useful combined with `StaticArray`) - `Hash`, `HTTP::Headers`, `HTTP::Params` and `ENV` now include the `Enumerable` module - `Proc` is now `Proc(*T, R)` - `Tuple(*T).new` and `NamedTuple(**T).new` now correctly match the given `T` ([#1828](https://github.com/crystal-lang/crystal/issues/1828)) - `Float64#to_s` now produces an ever more accurate output - `JSON` parsing now correctly handle floats with many digits - `JSON.mapping` and `YAML.mapping` now also accept named arguments in addition to a hash literal or named tuple literal - `Int#chr` now raises if the integer is out of a char's range. The old non-raising behaviour is now in `Int#unsafe_chr`. - The output of `pp x` is now `x # => ...` instead of `x = ...` - The output of the `debug()` macro method now tries to format the code (pass `false` to disable this) - Added `JSON` and `YAML` parsing and mapping for unions - Added `FileUtils.cp_r` (thanks @Dreauw) - Added `Tuple.from` and `NamedTuple.from` (thanks @jhass) - Added `XML.escape` (thanks @juanedi) - Added `HTTP::Server::Response#respond_with_error` (thanks @jhass) - Added `TCPServer#accept?` - Added optional `base` argument to `Char#digit?` and `Char#hex?` (thanks @mirek) - Added `flag?` macro method, similar to using `ifdef`. `ifdef` is deprecated and will be removed in a future version. - Added `YAML::PullParser#read_raw` - Added `Proc#partial` - Added `Socket.ip?(str)` to validate IPv4 and IPv6 addresses - Added `Bytes` as an alias of `Slice(UInt8)` - Added `RangeLiteral` macro methods: `begin`, `end`, `excludes_end?`, `map` and `to_a` - Added `ArrayLiteral#[range]` and `ArrayLiteral#[from, to]` in macros (applicable for `TupleLiteral` too) - Added `Generic` macro methods: `name`, `type_vars`, `named_args` - Spec: added JUnit formatter output (thanks @juanedi) - The `tls` option in `HTTP::Client` can now take a `OpenSSL::SSL::Context::Client` in addition to `true`. - `HTTP::LogHandler` logs exceptions now (thanks @jhass) - `HTTP::ErrorHandler` does not tell the client which exception occurred by default (can be enabled with a `verbose` flag) (thanks @jhass) - Several bug fixes ### 0.17.4 (2016-05-26) - Added string literals without interpolations nor escapes: `%q{...}` and `<<-'HEREDOC'`. Also added `%Q{...}` with the same meaning as `%{...}`. - A method that uses `@type` inside a macro expression is now automatically detected as being a `macro def` - `Float64#to_s` now produces a more accurate output - Added `Crystal::VERSION` and other compiler-metadata constants - Added `Object.from_json(string_or_io, root)` and a `root` option to `JSON.mapping` - Added `System.hostname` (thanks @miketheman) - The `property`, `getter` and `setter` macros now also accept assignments (`property x = 0`) - The `record` macro now also accepts assignments (`record Point, x = 0, y = 0`) - Comparison in macros between `MacroId` and `StringLiteral` or `SymbolLiteral` now work as expected (compares the `id` representation) - Some bug fixes ### 0.17.3 (2016-05-20) - Fixed: multiple macro runs executions didn't work well ([#2624](https://github.com/crystal-lang/crystal/issues/2624)) - Fixed incorrect formatting of underscore in unpacked block arguments - Fixed wrong codegen for global variable assignment in type declaration ([#2619](https://github.com/crystal-lang/crystal/issues/2619)) - Fixed initialize default arguments where evaluated at the class scope ([#731](https://github.com/crystal-lang/crystal/issues/731)) - The type guesser can now infer a block type from `def initialize(&@block)` - Allow type restriction in double splat argument (similar to restriction in single splat) - Allow splat restriction in splat argument (useful for `Tuple.new`) - Allow double splat restriction in double splat argument (useful for `NamedTuple.new`) ### 0.17.2 (2016-05-18) - Fixed crash when using pointerof of constant ### 0.17.1 (2016-05-18) - Constants and class vars are no longer initialized before "main". Now their initialization order goes along with "main", similar to how it works in Ruby (much more intuitive) - Added syntax for unpacking block arguments: `foo { |(x, y)| ... }` - Added `NamedTupleLiteral#map` and `HashLiteral#map` in macros (thanks @jhass) - Fixed wrong codegen for tuples/named tuples merge with pass-by-value types - Formatter: fixed incorrect format for named tuple type ### 0.17.0 (2016-05-17) - **(breaking change)** Macro defs are now parsed like regular methods. Enclose the body with `{% begin %} .. {% end %}` if you needed that behaviour - **(breaking change)** A union of two tuples of the same size results in a tuple with the unions of the types in each position. This only affects code that later tested a tuple's type with `is_a?`, for example `tuple.is_a?({Int32, String})` - **(breaking change)** Method arguments have now a different semantic. This only affects methods that had a splat argument followed by other arguments. - **(breaking change)** The syntax `{foo: 1, bar: 2}` now denotes a `NamedTuple`, not a `Hash` with symbol as keys. Use `{:foo => 1, :bar => 2}` instead - The syntax `exp as Type` is now deprecated and will be removed in the next version. Use `crystal tool format` to automatically upgrade your code - The compiler now gives an error when trying to define a method named `!`, `is_a?`, `responds_to?`, `nil?`, `as` or `as?` - Added the `NamedTuple` type - Added double splatting - Added external argument names - Macro defs return type is no longer mandatory - Added `as?`: similar to `as`, but returns `nil` when the type doesn't match - Added `Number::Primitive` alias - Added `Tuple#+(Tuple)` - Added `ArrayLiteral#+(ArrayLiteral)` in macros - `Crypto::MD5` now allows `Slice(UInt8)` and a block form (thanks @will) - Added docs for XML (thanks @Hamdiakoguz) - Many bug fixes ### 0.16.0 (2016-05-05) - **(breaking change)** Instance, class and global variables types must be told to the compiler, [either explicitly or through a series of syntactic rules](http://crystal-lang.org/docs/syntax_and_semantics/type_inference.html) - **(breaking change)** Non-abstract structs cannot be inherited anymore (abstract structs can), check the [docs](http://crystal-lang.org/docs/syntax_and_semantics/structs.html) to know why. In many cases you can use modules instead. - **(breaking change)** Class variables are now initialized at the beginning of the program (before "main"), make sure to read the docs about [class variables](http://crystal-lang.org/docs/syntax_and_semantics/class_variables.html) and [main](http://crystal-lang.org/docs/syntax_and_semantics/the_program.html) - **(breaking change)** Constants are now initialized at the beginning of the program (before "main"), make sure to read the docs about [constants](http://crystal-lang.org/docs/syntax_and_semantics/constants.html) and [main](http://crystal-lang.org/docs/syntax_and_semantics/the_program.html) - **(breaking change)** When doing `crystal program.cr arg1 arg2 arg3`, `arg1`, `arg2` and `arg3` are considered arguments to pass to the program (not the compiler). Use `crystal run program.cr arg1 ...` to consider `arg1` a file to include in the compilation. - **(breaking change)** `Int#**(Int)` now returns an integer, and raises if the argument is negative. Use a float base or exponent for negative exponents to work. - **(breaking change)** `Slice#to_s` and `StaticArray#to_s` now include their type name in the output - Support for FreeBSD and musl libc has landed (thanks @ysbaddaden) - The `.crystal` directory is now created at `$HOME/.cache/crystal` or `$HOME/.crystal` (or others similar), with a fallback to the current directory - `crystal doc` and `crystal tool hierarchy` are now much faster. Additionally, the hierarchy tool shows types for generic types, and doesn't show instantiations anymore (wasn't very useful) - `!` now does type filtering (for example you can do `!x || x.bar`, assuming `x` can be `nil` and the non-nil type responds to `bar`) - Named arguments can now match any argument, even if they don't have a default value. Make sure to read the [docs](http://crystal-lang.org/docs/syntax_and_semantics/default_and_named_arguments.html) - The `as` operator can now be written as a method: `exp.as(Type)` in addition to `exp as Type`. The old syntax will be removed in a few releases. - Added `@x : Int32 = 1` syntax (declaration + initialization) - `new`/`initialize` logic now works more as one would expect - Added `BigRational` (thanks @will) - Added `BigFloat` (thanks @Exilor) - Added `String#insert` - Added `Time::EpochConverter` and `Time::EpochMillisConverter` - Added `%s` (unix epoch) directive to `Time::Format` - `Time` now honours Dayling Saving and `ENV["TZ"]` - Added `HTTP::Server::Response#cookies` (thanks @jhass) - Added `Array#bsearch`, `Array#bsearch_index` and `Range#bsearch` (thanks @MakeNowJust) - Added `Range#reverse_each` iterator (thanks @omninonsense) - `JSON::Any`: added `as_...?` methods (thanks @DougEverly) - `JSON::Any` is now `Enumerable` - `YAML::Any` is now `Enumerable` - Added `JSON.parse_raw` that returns a `JSON::Type` - `JSON::PullParser`: added `#read_raw` to read a JSON value as a raw string (useful for delayed parsing). Also added `String::RawConverter` to be used with `JSON.mapping`. - `JSON` and `YAML`: enums, `BigInt` and `BigFloat` are now serializable - `ENV`: allow passing `nil` as a value to delete an environment variable - `Hash`: allow `Array | Tuple` arguments for `#select`, `#select!`, `#reject` and `#reject!` - `Crypto::Subtle.constant_time_compare` now returns `Bool`, and it can compare two strings in addition to two slices (thanks @skunkworker) - `HTTP::Server`: reset port zero after listening (thanks @splattael) - Added `File#each_line` iterator - Added `Number.slice`, `Number.static_array`, `Slice.[]` and `StaticArray.[]` to easily create slices and static arrays - Added `Slice#hexdump` (thanks @will) - Added `Enumerable#product` (thanks @dkhofer) - Fix: disallow using `out` with `Void*` pointers - Fixed bug in `XML::Node#namespace_scopes` (thanks @Hamdiakoguz) - Added docs for `INIFile` (thanks @EvanHahn) - Lots of bug fixes ### 0.15.0 (2016-03-31) - **(breaking change)** `!` has now its meaning hardcoded in the language. If you defined it for a type it won't be invoked as a method anymore. - **(breaking change)** `nil?` has now its meaning hardcoded in the language. If you defined it for a type it won't be invoked as a method anymore. - **(breaking change)** `typeof` is now disallowed in `alias` declarations - Added `crystal tool format --check` to check that source code is properly formatted - `crystal play` (playground) added workbooks support, as well as improvements and stabilizations - Added `Tempfile.dirname` (thanks @DougEverly) - Added `Path#resolve` method in macros - `{{...}}` arguments to a macro call are now expanded before macro invocation ([#2392](https://github.com/crystal-lang/crystal/issues/2392)) - Special variables (`$~` and `$?`) are now accessible after being defined in blocks ([#2194](https://github.com/crystal-lang/crystal/issues/2194)) - Some bugs and regressions fixed ### 0.14.2 (2016-03-22) - Fixed regression with formatter ([#2348](https://github.com/crystal-lang/crystal/issues/2348)) - Fixed regression with block return types ([#2347](https://github.com/crystal-lang/crystal/issues/2347)) - Fixed regression with openssl (https://github.com/crystal-lang/crystal/commit/78c12caf2366b01f949046e78ad4dab65d0d80d4) ### 0.14.1 (2016-03-21) - Fixed some regressions in the formatter ### 0.14.0 (2016-03-21) - **(breaking change)** The syntax of a method argument with a default value and a type restriction is now `def foo(arg : Type = default_value)`. The old `def foo(arg = default_value : Type)` was removed. - **(breaking change)** `Enumerable#take(n)` and `Iterator#take(n)` were renamed to `first(n)` - **(breaking change)** `Socket#addr` and `Socket#peeraddr` were renamed to `local_address` and `remote_address` respectively - **(breaking change)** Removed `Comparable#between?(a, z)`. Use `a <= x <= z` instead - **(breaking change)** `HTTP::WebSocketHandler` callbacks can now access the `HTTP::Context`. If you had a forwarding method to it you'll need to update it. See [#2313](https://github.com/crystal-lang/crystal/issues/2313). - New command `crystal play` that opens a playground for you to play in the browser :-) (thanks @bcardiff) - New command `crystal env` that prints environment information - `Spec`: you can now run multiple files with specified line numbers, as in `crystal spec file1.cr:10 file2.cr:20 ...` - Initial support for musl-libc (thanks @ysbaddaden) - Added `FileUtils.cp` (thanks @Dreauw) - Added `Array#first(n)` and `Array#last(n)` (thanks @greyblake) - Added `WebSocket#close` and properly handle disconnections - Added `UDPSocket#send` and `UDPSocket#receive` (thanks @tatey) - Added `Char#uppercase?` and `Char#lowercase?` (thanks @MaloJaffre`) - Added `sync_close` property to `OpenSSL::SSL::Socket`, `Zlib::Inflate` and `Zlib::Deflate` - Added `XML::Node#encoding` and `XML::Node#version` - Added `HTTP::Client::Response#success?` (thanks @marceloboeira) - Added `StaticArray#shuffle!(random)` (thanks @Nesqwik) - Added `Splat#exp` method in macros - Added fiber-safe `Mutex` - All `Int` types (except `BigInt`) can now be used in `JSON` and `YAML` mappings (thanks @marceloboeira) - Instance variable declarations/initializations now correctly work in generic classes and modules - Lots of bug fixes ### 0.13.0 (2016-03-07) - **(breaking change)** `Matrix` was moved to a separate shard: [https://github.com/Exilor/matrix](https://github.com/Exilor/Matrix) - The syntax of a method argument with a default value and a type restriction is now `def foo(arg : Type = default_value)`. Run `crystal tool format` to automatically upgrade existing code to this new syntax. The old `def foo(arg = default_value : Type)` syntax will be removed in a next release. - Special handling of `case` with a tuple literal. See [#2258](https://github.com/crystal-lang/crystal/pull/2258). - Keywords can now be used for variable declaration, so `property end : Time` works as expected. - Comparison of signed vs. unsigned integers now always give a correct result - Allow declaring instance variables in non-generic module types (`module Moo; @x : Int32; end`) - Allow initializing instance variables in non-generic module types (`module Moo; @x = 1; end`) - `Spec`: allow setting multiple output formatters (thanks @marceloboeira) - `StringScanner`: improved performance - Added `foo.[0] = 1` and `foo.[0]` as valid syntax, similar to the one in `&.` blocks (thanks @MakeNowJust) - `CSV`: allow separate and quote characters different than comma and double quote (thanks @jreinert) - `YAML`: support merge operator (`<<`) (thanks @jreinert) - Allow redefining primitive methods like `Int32#+(other : Int32)` - Allow defining macros with operator names like `[]` - `Levenshtein`: improved performance (thanks @tcrouch) - `HTTP::Client`: fixed incorrect parsing of chunked body - `HTTP::Client`: added a constructor with an `URI` argument (thanks @plukevdh) - `String`: `sub` and `gsub` now understand backreferences (thanks @bjmllr) - `Random`: added `Random#rand(Float64)` and `Random#rand(Range(Float, Float))` (thanks @AlexWayfer) - `HTML`: `HTML.escape` includes more characters (thanks @Ryuuzakis) - Added `TypeNode.class` method in macros (thanks @waterlink) - `run` inside macros now also work with absolute paths (useful when used with `__DIR__`) - Added docs for `Math` and `StaticArray` (thanks @Zavydiel, @HeleneMyr) - Many bug fixes and some micro-optimizations ### 0.12.0 (2016-02-16) - **(breaking change)** When used with a type declaration, the macros `property`, `getter`, `setter`, etc., declare instance variables with those types. - **(breaking change)** `JSON.mapping` and `YAML.mapping` declare instance variables with the given types. - **(breaking change)** `YAML.load` was renamed to `YAML.parse`, and it now returns a `YAML::Any`. - **(breaking change)** `embed_ecr` and `ecr_file` were renamed to `ECR.embed` and `ECR.def_to_s` (the old methods now produce a warning and will be removed in the next release). - Added encoding support: `IO#set_encoding`, `String#encode`, and `HTTP::Client` charset check. - Segmentation faults are now trapped and shown in a more friendlier way. - The `record` macro can now accept type declarations (for example `record Point, x : Int32, y : Int32`) - Added `Iterator#step` (thanks @jhass) - `Array#push` and `Array#unshift` can now accept multiple values and add the elements in an efficient way (thanks @arktisklada) - Added `default` option to `JSON.mapping` (thanks @kostya) - Added `default` option to `YAML.mapping` (thanks @jreinert) - Allow doing `case foo; when Foo.class` (and `Foo(T)` and `Foo(T).class`) in case expressions. - Added `Class#|` so a union type can be expresses as `Int32 | Char` in regular code. - Added `File.real_path` (thanks @jreinert) - Added `dns_timeout` for `HTTP::Client` (thanks @kostya) - Added dynamic width precision to `sprintf` (thanks @gtramontina) - `Markdown` now supports blockquotes and 1 level of list nesting (thanks @SebastianSzturo) - `p` now accepts multiple arguments - Many bug fixes and some optimizations ### 0.11.1 (2016-01-25) - Fixed [#2050](https://github.com/crystal-lang/crystal/issues/2050), [#2054](https://github.com/crystal-lang/crystal/issues/2054), [#2057](https://github.com/crystal-lang/crystal/issues/2057), [#2059](https://github.com/crystal-lang/crystal/issues/2059), [#2064](https://github.com/crystal-lang/crystal/issues/2064) - Fixed bug: HTTP::Server::Response headers weren't cleared after each request - Formatter would incorrectly change `property x :: Int32` to `property x = uninitialized Int32` ### 0.11.0 (2016-01-23) - **(breaking change)** Syntax for type declarations changed from `var :: Type` to `var : Type`. The old syntax is still allowed but will be deprecated in the next version (run `crystal tool format` to automatically fix this) - **(breaking change)** Syntax for uninitialized variables, which used to be `var :: Type`, is now `var = uninitialized Type`. The old syntax is still allowed but will be deprecated in the next version (run `crystal tool format` to automatically fix this) - **(breaking change)** `HTTP::Server` refactor to support streaming. Check the [docs](http://crystal-lang.org/api/HTTP/Server.html) of `HTTP::Server` for upgrade instructions - **(breaking change)** Renamed `HTTP::WebSocketSession` to `HTTP::WebSocket`. - **(breaking change)** Heredocs now remove indentations according to the indentation of the closing identifier (thanks @rhysd) - **(breaking change)** Renamed `Enumerable#inject` to `Enumerable#reduce` - **(breaking change)** `next` and `return` semantic inside captured block has been swapped ([#420](https://github.com/crystal-lang/crystal/issues/420)) - Fibers context switch is now faster, done with inline assembly. `libpcl` is no longer used - Allow annotating the type of class and global variables - Support comments in ECR (thanks @ysbaddaden) - Security improvements to `HTTP::StaticFileHandler` (thanks @MakeNowJust) - Moved `seek`, `tell`, `pos` and `pos=` from `File` to `IO::FileDescriptor` (affects `Tempfile`) - `URI.parse` is now faster (thanks @will) - Many bug fixes, some really old ones involving issues with order of declaration ### 0.10.2 (2016-01-13) - Fixed Directory Traversal Vulnerability in HTTP::StaticFileHandler (thanks @MakeNowJust) ### 0.10.1 (2016-01-08) - Added `Int#popcount` (thanks @rmosolgo) - Added `@[Naked]` attribute for omitting a method's prelude - Check that abstract methods are implemented by subtypes - Some bug fixes ### 0.10.0 (2015-12-23) - **(breaking change)** `def` arguments must always be enclosed in parentheses - **(breaking change)** A space is now required before and after def return type restriction - **(breaking change)** Renamed `Dir.working_dir` to `Dir.current` - **(breaking change)** Moved `HTML::Builder` to [its own shard](https://github.com/crystal-lang/html_builder) - **(breaking change)** `String#split` now always keeps all results (never drops trailing empty strings) - **(breaking change)** Removed `Array#buffer`, `StaticArray#buffer` and `Slice#buffer`. Use `to_unsafe` instead (so unsafe usages are easier to spot) - **(breaking change)** Removed `String#cstr`. Use `to_unsafe` instead (so unsafe usages are easier to spot) - Optimized Range#sum (thanks @MakeNowJust) - Allow forward declarations for lib external vars - Added `Int#to_s(base)` for `base = 62` (thanks @jhass) - `JSON.parse` now returns `JSON::Any`, which allows traversal of JSON objects with less casts - Added `OpenSSL::PKCS5` (thanks @benoist) - MemoryIO can now be created to read/write from a Slice(UInt8). In this mode MemoryIO can't be expanded, and can optionally be written. And when creating a MemoryIO from a String, it's non-resizeable and read-only. - Added `Object#!~` (the opposite of `=~`) - `at_exit` now receives that exit status code in the block (thanks @MakeNowJust) - Allow using `Set` in JSON mappings (thanks @benoist) - Added `File.executable?`, `File.readable?` and `File.writeable?` (thanks @mverzilli) - `Array#sort_by` and `Array#sort_by!` now use a [Schwartzian transform](https://en.wikipedia.org/wiki/Schwartzian_transform) (thanks @radarek) - Added `Array#each_permutation`, `Array#each_combination` and `Array#each_repeated_combination` iterators - Added optional _random_ argument to `Array#sample` and `Array#shuffle` - The `delegate` macro can now delegate multiple methods to an object (thanks @elthariel) - Added basic YAML generation (thanks @porras) ### 0.9.1 (2015-10-30) - Docs search now finds nested entries (thanks @adlerhsieh) - Many corrections and changes to the formatter, for better consistency and less obtrusion. - Added `OpenSSL::Cipher` and `OpenSSL::Digest` (thanks @benoist) - Added `Char#+(String)` (thanks @hangyas) - Added `Hash#key` and `Hash#key?` (thanks @adlerhsieh) - Added `Time::Span#*` and `Time::Span#/` (thanks @jbaum98) - Added `Slice#reverse_each` (thanks @omninonsense) - Added docs for `Random` and `Tempfile` (thanks @adlerhsieh) - Fixed some bugs. ### 0.9.0 (2015-10-16) - **(breaking change)** The `CGI` module's functionality has been moved to `URI` and `HTTP::Params` - **(breaking change)** `IO#read()` is now `IO#gets_to_end`. Removed `IO#read(count)`, added `IO#skip(count)` - **(breaking change)** `json_mapping` is now `JSON.mapping`. `yaml_mapping` is now `YAML.mapping` - **(breaking change)** `StringIO` is now `MemoryIO` - Added `crystal tool format` that automatically formats your code - `protected` methods can now be invoked between types inside a same namespace - Removed `curses`, you can use `https://github.com/jreinert/ncurses-crystal` - `to_unsafe` and numeric conversions are now also automatically performed in C struct and union fields - Added `{% begin %} ... {% end %}` as an alternative to `{% if true %} ... {% end %}` - Added `~!` operator - Added debug metadata for char, float, bool and enums. Also for classes and structs (experimental) - `Dir.glob` now works well with recursive patterns like `**` (thanks @pgkos) - Added `read_timeout` and `connect_timeout` to `HTTP::Client` (thanks @benoist) - Added `Zlib` (thanks @datanoise and @bcardiff) - Added `HTTP::DeflateHandler` (thanks @bcardiff) - Added `ENV#fetch` (thanks @tristil) - `Hash#new` now accepts an initialize capacity argument - `HTTP::Request` provides access and mutation of `query`, `path` and `query_params` (thanks @waterlink) - Added `XML::Node#content=` and `#name=` - Allow passing handlers and a block to an `HTTP::Server` (thanks @RX14) - `crystal init` now tries to use your github username if available (thanks @jreinert) - Added `Hash#select`, `Hash#reject` and their bang variant, and `Hash#each_with_object` (thanks @devdazed) - Added `Hash#select(*keys)` and `Hash#reject(*keys)` and their bang variant (thanks @sdogruyol) - Added `Set#-`, `Set#^`, and `Set#subtract` (thanks @js-ojus) - Allow running specs without colors (thanks @rhysd) - Added `TypeNode#has_constant?` and `TypeNode#type_vars` in macros (thanks @jreinert) - Added `String#compare` that allows case insensitive comparisons - Added `File#truncate` (thanks @porras) - `CSV` is now a class for iterating rows, optionally with headers access - Allow setting multiple `before_request` callbacks to an `HTTP::Client` - Added `Dir.cd(&block)` (thanks @rhysd) - Added `Class#cast` (thanks @will) - Fixes and additions to WebSocket, like the possibility of streaming data (thanks @jreinert) - Added `SemanticVersion` class (thanks @technorama) - `loop` now yields a counter - Added `Array#[]=(index, count, value)` and `Array#[]=(range, value)` - Added argless `sleep` - `IO#write(slice)` now writes the full slice or raises on error - Added some docs for ECR, Markdown, Hash, File, Time, Time::Span, Colorize, String, SecureRandom, YAML (thanks @adlerhsieh, @chdorner, @vjdhama, @rmosolgo) - Many bug fixes ### 0.8.0 (2015-09-19) - **(breaking change)** Renamed a couple of types: `ChannelClosed` -> `Channel::ClosedError`, `UnbufferedChannel` -> `Channel::Unbuffered`, `BufferedChannel` -> `Channel::Buffered`, `DayOfWeek` -> `Time::DayOfWeek`, `MonthSpan` -> `Time::MonthSpan`, `TimeSpan` -> `Time::Span`, `TimeFormat` -> `Time::Format`, `EmptyEnumerable` -> `Enumerable::EmptyError`, `SocketError` -> `Socket::Error`, `MatchData` -> `Regex::MatchData`, `SignedInt` -> `Int::Signed`, `UnsignedInt` -> `Int::Unsigned`, `FileDescriptorIO` -> `IO::FileDescriptor`, `BufferedIO` -> `IO::Buffered`, `CharReader` -> `Char::Reader`, `PointerAppender` -> `Pointer::Appender`. - **(breaking change)** All places that raised `DomainError` raise `ArgumentError` now. - **(breaking change)** Renamed `Type.cast` to `Type.new` (for example, `Int32.new` instead of `Int32.cast`) - **(breaking change)** Removed all macro instance variables except `@type` - **(breaking change)** Removed `undef` - **(breaking change)** Removed `length()` and `count()` methods from collections. The only method for this is now `size`. - **(breaking change)** Removed the ability to invoke methods on a union class - Improved debugger support - `crystal deps` now delegates to [shards](https://github.com/ysbaddaden/shards). Removed `Projecfile` support. - Automatically convert numeric types when invoking C functions - Automatically define questions methods for enum members - Support quotes inside quoted symbols (thanks @wolflee) - Allow marking `initialize` as private - Added `method_added` macro hook (thanks @MakeNowJust) - Added `ArrayLiteral#includes?(obj)` in macros - Added `ASTNode#symbolize` in macros (thanks @kirbyfan64) - Added experimental `yaml_mapping` - Added nilable variants to `Enumerable#max`, `Enumerable#min`, and others (thanks @technorama) - Added `Iterator#flatten` (thanks @jpellerin) - Added setting a read timeout to `HTTP::Client` (thanks @benoist) - Added `Array#delete_at(index, count)` and `Array#delete_at(range)` (thanks @tebakane) - Added `HTTP::Cookies` (thanks @netfeed) - Added `Tuple#reverse` (thanks @jhass) - Added `Number#clamp` (thanks @technorama) - Added several socket options (thanks @technorama) - Added `WebSocket.open` (thanks @kumpelblase2) - Added `Enum.flags` macro - Added support for sending chunked content in HTTP server (thanks @bcardiff) - Added `future`, `lazy` and `delay` concurrency methods (thanks @technorama) - `fork` now returns a `Process` (thanks @technorama) - Documented `Set`, and added a couple of methods (thanks @will) - Nicer formatting in `Benchmark.ips`, and interactive mode (thanks @will) - The `-f` format output is now honored in compiler errors (thanks @kirbyfan64) - Fixed an ambiguity with the `crystal build` command (thanks @MakeNowJust) - Cast exceptions now raise `TypeCastError` instead of `Exception` (thanks @will) - Many bugs fixes ### 0.7.7 (2015-09-05) - **(breaking change)** Reimplemented `Process.run` to allow configuring input, output and error, as well as behaving well regarding non-blocking IO (thanks @technorama) - **(breaking change)** Removed the `alias_method` macro. - **(breaking change)** Disallow declaring defs, classes and other declarations "dynamically" (for example inside an `if`... this of course didn't work, but incorrectly compiled). - **(breaking change)** `require` is now only allowed at the top-level, never inside other types or methods. - **(breaking change)** Removed `Nil#to_i` - **(breaking change)** Changed API of `Channel#select` toward a thread-safe one. - **(breaking change)** The two methods that IO must implement are now `read(slice : Slice(UInt8))` and `write(slice : Slice(UInt8))`. - New beautiful, searchable and more functional API docs. Thanks @rosylilly for the initial design, and @BlaxPirit for some improvements. - CLI: Moved `browser`, `hierarchy` and `types` to `crystal tool ...` - Added `crystal tool context` and `crystal tool implementations` for IDEs (thanks @bcardiff!!) - `Int#>>(amount)` and `Int#<<(amount)` now give zero when `amount` is greater than the number of bits of the integer representation. - Added `\%` escape sequence inside macros. - Added aliases for the many C types (thanks @BlaxPirit) - Added `Iterator#in_groups_of` (thanks @PragTob) - Added optional `offset` argument to `Hash#each_with_index` (thanks @sergey-kucher) - Added `Array#combinations`, `Array#each_combination`, `Array#repeated_combinations`, `Array#each_repeated_combination`, `Array#repeated_permutations`, `Array#each_repeated_permutation`, `Array.product` and `Array.each_product` (thanks @kostya) - Added `Array#rotate` and `Array#rotate!` (thanks @kostya) - Added `MatchData#pre_match` and `MatchData#post_match` (thanks @bjmllr) - Added `Array#flatten` - Added `Range.reverse_each`, along with `Int#pred` and `Char#pred` (thanks @BlaxPirit) - Added `XML.parse_html` (thanks @ryanworl) - Added `ENV.keys` and`ENV.values` (thanks @will) - Added `StaticArray==(other : StaticArray)` (thanks @tatey) - Added `String#sub` in many variants (thanks @jhass) - Added `Readline.bind_key`, `Readline.unbind_key`, `Readline.done` and `Readline.done=` (thanks @daphee) - Added `Hash#all?`, `Hash#any?` and `Hash#inject` (thanks @jreinert) - Added `File#pos` and `File#pos=` - Added `Enum.from_value` and `Enum.from_value?` - Added `Deque` (thanks @BlaxPirit) - Added lots of methods to `StringScanner`, and documented it, making it usable (thanks @will) - `StringIO` now quacks like a `File`. - Allow sending masked data through a `WebSocket`, and sending long data (thanks @kumpelblase2) - `File.new` now accepts an optional `perm` argument (thanks @technorama) - `FileDescriptorIO` now has configurable read/write timeouts (thanks @technorama) - Signal handling is more robust and allows any kind of code (thanks @technorama) - Correctly handle `WebSocket` close packet (thanks @bebac) - Correctly implement `seek` and `tell` in buffered IOs (thanks @lbguilherme) - Allow setting several options on sockets (thanks @technorama) - Some improvements to `crystal init` for the "app" case (thanks @krisleech) - `sleep` and IO timeouts can receive `TimeSpan` as arguments (thanks @BlaxPirit) - Handle `HTTP::Response` without content-length (thanks @lbguilherme) - Added docs for OptionParser, ENV, Regex, Enumerable, Iterator and some Array methods (thanks @porras, @will, @bjmllr, @PragTob, @decioferreira) - Lots of bug fixes and small improvements ### 0.7.6 (2015-08-13) - **(breaking change)** removed support for trailing `while`/`until` ([read this](https://github.com/crystal-lang/crystal/wiki/FAQ#why-trailing-whileuntil-is-not-supported-unlike-ruby)) - **(breaking change)** Renamed `Enumerable#drop` to `Enumerable#skip` - **(breaking change)** Renamed `Time.at` to `Time.epoch`, and `Time#to_i` and `Time#to_f` to `Time#epoch` and `Time#epoch_f` - **(breaking change)** `inherited` macro now runs before a class' body - Renamed `--no-build` flag to `--no-codegen` - Allow interpolations in heredocs (thanks @jessedoyle) - Allow hash substitutions in `String#%` and `sprintf` (thanks @zamith) - Added `SecureRandom.base64`, `SecureRandom.urlsafe_base64` and `SecureRandom.uuid` (thanks @ysbaddaden) - Added `File.link`, `File.symlink` and `File.symlink?` (thanks @ysbaddaden) - Added `Enumerable#in_groups_of` (thanks @jalyna) - Added `Array#zip?` (thanks @yui-knk) - Added `Array#permutations` and `Array#each_permutation` (thanks @jalyna and @kostya) - Added `IO#gets(limit : Int)` and `IO#gets(delimiter : Char, limit : Int)` - Added `Iterator#compact_map`, `Iterator#take_while` and `Iterator#skip_while` (thanks @PragTob) - Added `StringLiteral#to_i` macro method - Added `Crypto::Bcrypt` (thanks @akaufmann) - Added `Time.epoch_ms` and `Time#epoch_ms` - Added `BitArray#toggle` and `BitArray#invert` (thanks @will) - Fixed `IO#reopen` swapped semantic (thanks @technorama) - Many bug fixes and improvements ### 0.7.5 (2015-07-30) - **(breaking change)** `0` is not a prefix for octal numbers anymore. Use `0o` - **(breaking change)** Renamed `MissingKey` to `KeyError` - **(breaking change)** Renamed `IndexOutOfBounds` to `IndexError` - Fixed all exception-handling related bugs. - Allow nested and multiline ternary expressions (thanks @daviswahl) - Allow assigning to `_` (underscore), give error when trying to read from it - Macros can now also receive the following nodes: `And`, `Or`, `Case`, `RangeLiteral` and `StringInterpolation`. `And` and `Or` have `left` and `right` methods. - Added `-e` option to `hierarchy` command to filter types by a regex - Added `-v` as an alias of `--version` - Added `-h` as an alias of `--help` - Added `Array#transpose` (thanks @rhysd) - Added `Benchmark#ips` (thanks @will) - Added `Hash#merge(&block)` and `Hash#merge!(&block)` (thanks @yui-knk) - Added `Hash#invert` (thanks @yui-knk) - Added `Bool#^` (thanks @yui-knk) - Added `Enumerable#drop`, `Enumerable#drop_while` and `Enumerable#take_while` (thanks @PragTob) - Added `Enumerable#none?` (thanks @yui-knk) - Added `Set#subset?`, `Set#superset?` and `Set#intersects?` (thanks @yui-knk) - Added `Set#new(Enumerable)` (thanks @yui-knk) - Added `String#succ` (thanks @porras and @Exilor) - Added `Array#*` (thanks @porras) - Added `Char#===(Int)` and `Int#===(Char)` (thanks @will) - Added `StringLiteral#camelcase` and `StringLiteral#underscore` in macros - Added `Expressions#expressions` in macros - Added `Cast#obj` and `Cast#to` in macros - Added `ASTNode#class_name` in macros (thanks @yui-knk) - Added `Array#push`/`Array#<<` and `Array#unshift` in macros (thanks @ysbaddaden) - Added `Def#visibility` in macros (thanks @ysbaddaden) - Added `String#codepoints` and `String#each_codepoint` (thanks @jhass) - `Char#to_i(base)` now supports bases from 2 to 36 - `Set#|` now correctly accepts a set of a possible different type (thanks @yui-knk) - Flush `STDERR` on exit (thanks @jbbarth) - `HTTP::Client` methods accept an optional block, which will yield an `HTTP::Response` with a non-nil `body_io` property to consume the response's IO - Document `URI`, `UDPSocket` (thanks @davydovanton) - Improved `URI` class (thanks @will) - Define `$~` in `String#gsub` and `String#scan` - Define `$?` in `Process.run` - Lots of bug fixes and small improvements ### 0.7.4 (2015-06-23) - Added Float module and remainder (thanks @wmoxam) - Show elapsed time in HTTP::LogHandler (thanks @zamith for the suggestion) - Added `0o` as a prefix for octal numbers (thanks @asb) - Allow spaces before the closing tag of a heredoc (thanks @zamith) - `String#split(Regex)` now includes captures in the results - Added `union?`, `union_types` and `type_params` in macro methods - Improved `MatchData#to_s` to show named groups (thanks @will) - Optimized Base64 encode/decode (thanks @kostya) - Added basic docs for spec (thanks @PragTob) - Added docs for Benchmark (thanks @daneb) - Added `ARGF` - Non-matching regex captures now return `nil` instead of an empty string (thanks @will) - Added `$1?`, `$2?`, etc., as a nilable alternative to `$1`, `$2`, etc. - Added user, password, fragment and opaque to URI (thanks @will) - `HTTP::Client.exec` now honors user/password info from URI - Set default user agent in `HTTP::Client` - Added `String#chop` - Fixed `crystal deps` behaviour with empty git repositories (thanks @tkrajcar) - Optimized `HTTP::Headers` and `HTTP::Request` parsing. - `FileDescriptorIO` (superclass of `File` and `Socket`) has now buffering capabilities (use `sync=` and `sync?` to turn on/off). That means there's no need to use `BufferedIO` for these classes anymore. - Allow `pointerof` with class and global variables, and also `foo.@bar` access - Optimized fibers performance. - Added inline assembly support. - The `.crystal` cache dir is now configurable with an ENV variable (thanks @jhass) - Generic type variables names can now also be a single letter followed by a digit. ### 0.7.3 (2015-06-07) - Added `Tuple.from_json` and `Tuple.to_json` - The `method_missing` macro now accepts a 1 argument variant that is a Call node. The 3 arguments variant will be deprecated. - Flush STDOUT at program exit (fixes `print` not showing any output) - Added `Time#to_utc` and `Time#to_local` (thanks @datanoise) - Time comparison is now correct when comparing local vs. utc times - Support timezone offsets in Time parsing and formatting - Added `IO#gets(delimiter : String)` - Added `String#chomp(Char)` and `String#chomp(String)` - Allow invoking `debug()` inside a macro to see what's being generated. - `IO#puts` and `IO#print` now receive a splat (thanks @rhysd) - Added `Process.kill` and `Process.getpgid` (thanks @barachy) - `Signal` is now an enum. Use it like `Signal::INT.trap { ... }` instead of `Signal.trap(Signal::INT) { ... }` - Added `CSV.each_row` (both in block and iterator forms) - Important fixes to non-blocking IO logic. ### 0.7.2 (2015-05-26) - Improved performance of Regex - Fixed lexing of octal characters and strings (thanks @rhysd) - Time.parse can return UTC times (thanks @will) - Handle dashes in `crystal init` (thanks @niftyn8) - Generic type variables can now only be single letters (T, U, A, B, etc.) - Support `%x` and `%X` in `sprintf` (thanks @yyyc514) - Optimized `Int#to_s` (thanks @yyyc514) - Added `upcase` option to `Int#to_s`, and use downcase by default. - Improved `String#to_i` and fixed the many variants (`to_i8`, `to_u64`, etc.) - Added `Time.at` (thanks @jeromegn) - Added `Int#upto`, `Int#downto`, `Int#to` iterators. - Added `Iterator#cons` and `Enumerable#each_cons` (thanks @porras) - Added `Iterator.of`, `Iterator#chain` and `Iterator#tap`. - Allow top-level `private macro` (similar to top-level `private def`) - Optimized `BufferedIO` writing performance and memory usage. - Added `Channel#close`, `Channel#closed?`, `Channel#receive?` and allow them to send/receive nil values (thanks @datanoise). - Fixed `Process#run` after introducing non-blocking IO (thanks @will) - `Tuple#map` now returns a `Tuple` (previously it returned an `Array`) - `Tuple#class` now returns a proper `Class` (previously it returned a `Tuple` of classes) - Lots of bug fixes. ### 0.7.1 (2015-04-30) - Fixed [#597](https://github.com/crystal-lang/crystal/issues/597). - Fixed [#599](https://github.com/crystal-lang/crystal/issues/599). ### 0.7.0 (2015-04-30) - Crystal has evented IO by default. Added `spawn` and `Channel`. - Correctly support the X86_64 and X86 ABIs. Now bindings to C APIs that pass and return structs works perfectly fine. - Added `crystal init` to quickly create a skeleton library or application (thanks @waterlink) - Added `--emit` flag to the compiler. Now you can easily see the generated LLVM IR, LLVM bitcode, assembly and object files. - Added `--no-color` flag to suppress color output, useful for editor tools. - Added macro vars: `%var` and `%var{x, y}` create uniqely named variables inside macros. - Added [typed splats](https://github.com/crystal-lang/crystal/issues/291). - Added `Iterator` and many methods that return iterators, like `Array#each`, `Hash#each`, `Int#times`, `Int#step`, `String#each_char`, etc. - Added `sprintf` and improved `String#%` to support floats and float formatting. - Added more variants of `String#gsub`. - Added `Pointer#clear` and use it to clear an `Array`'s values when doing `pop` and other shrinking methods. - Added `BigInt#to_s(base)`, `BigInt::cast` and bit operators (thanks @Exilor) - Allow invoking methods on a union class as long as all types in the union have it. - Allow specifying a def's return type. The compiler checks the return type only for that def for now (not for subclasses overriding the method). The return type appears in the documentation. - Allow constants and computed constants for a StaticArray length. - Allow class vars in enums. - Allow private and protected defs in enums. - Allow reopening a `lib` and adding more `@[Link]` attributes to it, even allowing duplicated attributes. - Allow getting a function pointer to a lib fun without specifying its types (i.e. `->LibC.getenv`) - Allow specifying `ditto` for a doc comment to reuse the previous comment. - Changed the semantic of `%`: previously it meant `remainder`, not it means `modulo`, similar to Ruby and Python. Added `Int#remainder`. - `#to_s` and `#inspect` now work for a union class. - Spec: added global `before_each` and `after_each` hooks, which will simplify the use of mocking libraries like [timecop.cr](https://github.com/waterlink/timecop.cr) and [webmock.cr](https://github.com/manastech/webmock.cr). - `Range(T)` is now `Range(B, E)` again (much more flexible). - Improved Regex performance. - Better XML support. - Support LLVM 3.6. - Exception class is now shown on unhandled exceptions - The following types are now disallowed in generics (for now): Object, Value, Reference, Number, Int and Float. - Lots of bug fixes, enhancements and optimizations. ### 0.6.1 (2015-03-04) - The `class` method now works in all cases. You can now compare classes with `==` and ask their `hash` value. - Block variables can now shadow local variables. - `Range(B, E)` is now `Range(T)`. - Added `Number::[]`. Now you can do `Int64[1, 2, 3]` instead of `[1_i64, 2_i64, 3_u64]`. - Better detection of nilable instance variables, and better error messages too. - Added `Crypto::Blowfish` (thanks @akaufmann) - Added `Matrix` (thanks @Exilor) - Added `CallConvention` attribute for `fun`s. - Macros: added `constants` so you can inspect a type's constants at compile time. - Macros: added `methods`, which lists a type's methods (without including supertypes). - Macros: added `has_attribute?` for enum types, so you can check if an enum has the Flags attribute on it. - Many more small additions and bug fixes. ### 0.6.0 (2015-02-12) - Same as 0.5.10 ### 0.5.10 (transitional) (2015-02-12) - **Note**: This release makes core, breaking changes to the language, and doesn't work out of the box with its accompanying standard library. Use 0.6.0 instead. - Improved error messages related to nilable instance variables. - The magic variables `$~` and `$?` are now method-local and concurrent-safe. - `Tuple` is now correctly considered a struct - `Pointer` is now correctly considered a struct - Renamed `Function` to `Proc` ### 0.5.9 (2015-02-07) - `Random` is now a module, with static methods that default to the `Random::MT19937` class. - Added `Random::ISAAC` engine (thanks @ysbaddaden!) - Added `String#size` (thanks @zamith!) - Added `limit` to all `String#split` variants (thanks @jhass!) - Raising inside a Thread is now rescued and re-raised on join (thanks @jhass!) - Added `path` option to Projectfile for `crystal deps` (thanks @naps62!) - Many fixes towards making Crystal work on linux 32 bits. - Huge refactors, additions and improvements for sockets: Socket, IPSocket, TCPSocket, TCPServer, UDPSocket, UNIXSocket, UNIXServer (thanks @ysbaddaden!) - Allow regex with empty spaces in various places. - Added `HTML.escape(String)` (thanks @naps62!) - Added support for `%w[...]`, `%w{...}`, `%w<...>` as alternatives to `%w(...)`. Same goes for `%i(...)` (thanks @zamith!) - Added `Enumerable#min_of`, `Enumerable#max_of` and `Enumerable#minmax_of`, `Enumerable#to_h`, `Dir.chdir` and `Number#fdiv` (thanks @jhass!) - Added `String#match`, `String#[]`, `String#[]?` and `MatchData#[]?` related to regexes (thanks @jhass!) - Allow `T::Bar` when T is a generic type argument. - Added `subclasses` and `all_subclasses` in macros. - Now you can invoke `to_s` and `inspect` on C structs and unions, making debugging C bindings much easier! - Added `#to_f` and `#to_i` to `Time` and `TimeSpan` (thanks @epitron!) - Added `IO.select` (thanks @jhass!) - Now you can use `ifdef` inside C structs and unions. - Added `include` inside C structs, to include other struct fields (useful for composition and avoiding an explicit indirection). - Added `Char#in_set?`, `String#count`, `String#delete` and `String#squeeze` (thanks @jhass!) - Added `-D flag` option to the compiler to set compile-time flags to use in `ifdef`. - More support for forward declarations inside C libs. - Rewritten some `Function` primitives in Crystal itself, and added methods for obtaining the pointer and closure data, as well as for recreating a function from these. - Added a `Logger` class (thanks @ysbaddaden!) - Lots of bugs fixed. ### 0.5.8 (2015-01-16) - Added `Random` and `Random::MT19937` (Mersenne Twister) classes (thanks @rhysd). - Docs: removed automatic linking. To link to classes and methods surround with backticks. - Fixed [#328](https://github.com/crystal-lang/crystal/issues/328): `!=` bug. ### 0.5.7 (2015-01-02) - Fixed: `doc` command had some hardcoded paths and didn't work - Added: `private def` at the top-level of a file is only available inside that file ### 0.5.6 (2014-31-12) - Added a `crystal doc` command to automatically generate documentation for a project using [Markdown](http://daringfireball.net/projects/markdown/) syntax. The style is still ugly but it's quite functional. Now we only need to start documenting things :-) - Removed the old `@:` attribute syntax. - Fixed [#311](https://github.com/crystal-lang/crystal/issues/311): Issues with invoking lib functions in other ways (thanks @scidom). - Fixed [#314](https://github.com/crystal-lang/crystal/issues/314): NoReturn information is not lazy. - Fixed [#317](https://github.com/crystal-lang/crystal/issues/317): Fixes in UTF-8 encoding/decoding (thanks @yous). - Fixed [#319](https://github.com/crystal-lang/crystal/issues/319): Unexpected EOF (thanks @Exilor). - `{{yield}}` inside macros now preserve the yielded node location, leading to much better error messages. - Added `Float#nan?`, `Float#infinite?` and `Float#finite?`. - Many other bug fixes and improvements. ### 0.5.5 (2014-12-12) - Removed `src` and crystal compiler `libs` directory from CRYSTAL_PATH. - Several bug fixes. ### 0.5.4 (2014-12-04) - **(breaking change)** `require "foo"` always looks up in `CRYSTAL_PATH`. `require "./foo"` looks up relative to the requiring file. - **(breaking change)** Renamed `Json` to `JSON`, `Xml` to `XML` and `Yaml` to `YAML` to follow [a convention](https://github.com/crystal-lang/crystal/issues/279). - **(breaking change)** To use HTTP types do, for example, `require "http/client"` instead of the old `require "net/http"`. - Added `alias_method` macro (thanks @Exilor and @jtomschroeder). - Added some `Complex` number methods and many math methods, refactors and specs (thanks @scidom). - Inheriting generic classes is now possible. - Creating arrays of generic types (i.e.: `[] of Thread`) is now possible. - Allow using an alias in a block type (i.e.: `alias F = Int32 ->`, `&block : F`). - `json_mapping` macro supports a simpler syntax: `json_mapping({key1: Type1, key2: Type2})`. - Spec: added `be_a(type)` matcher. - Spec: added `be > ...` and similar matchers for `>=`, `<` and `<=`. - Added `File::file?` and `File::directory?`. - CSV parser can parse from String or IO. - When invoking the compiler like this: `crystal foo.cr -o foo` the `build` command is assumed instead of `run`. - Added short symbol notation for methods that are operators (i.e. `:+`, `:*`, `:[]`, etc.). - Added `TimeSpan#ago`, `TimeSpan#from_now`, `MonthSpan#ago` and `MonthSpan#from_now`. ### 0.5.3 (2014-11-06) - Spec: when a `should` or `should_not` fail, the filename and line number, including the source's line, is included in the error message. - Spec: added `-l` switch to be able to run a spec defined in a line. - Added `crystal spec file:line` - Properties (property, setter, getter) can now be restricted to a type with the syntax `property name :: Type`. - Enums can be used outside `lib`. They inherit `Enum`, can have methods and can be marked with @[Flags]. - Removed the distinction between `lib` enums and regular enums. - Fixed: it was incorrectly possible to define `class`, `def`, etc. inside a call block. - The syntax for specifying the base type of an enum, `enum Name < BaseType` has been deprecated. Use `enum Name : BaseType`. - Added `Array#<=>` and make it comparable to other arrays. ### 0.5.2 (2014-11-04) - New command line interface to the compiler (`crystal build ...`, `crystal run ...`, `crystal spec`, etc.). The default is to compiler and run a program. - `crystal eval` without arguments reads from standard input. - Added preliminar `crystal deps` command. - `__FILE__`, `__DIR__` and `__LINE__`, when used as def default arguments, resolve to the caller location (similar to [D](http://dlang.org/traits.html#specialkeywords) and [Swift](https://developer.apple.com/swift/blog/?id=15)) - Allow `as` to determine a type even if the casted value doesn't have a type yet. - Added `is_a?` in macros. The check is against an [AST node](https://github.com/crystal-lang/crystal/blob/master/src/compiler/crystal/syntax/ast.cr) name. For example `node.is_a?(HashLiteral)`. - Added `emit_null` property to `json_mapping`. - Added `converter` property to `json_mapping`. - Added `pp` in macros. - Added `to_pretty_json`. - Added really basic `CSV.parse`. - Added `Regex.escape`. - Added `String#scan`. - Added `-e` switch to spec, to run specs that match a pattern. - Added `--fail-fast` switch to spec. - Added `HTTPClient#basic_auth`. - Added `DeclareVar`, `Def` and `Arg` macro methods. - Added `Time` and `TimeSpan` structs. `TimeWithZone` will come later. - Added `Array#fill` (thanks @Exilor). - Added `Array#uniq`. - Optimized `File.read_lines`. - Allow any expression inside `{% ... %}` so that you can interpret code without outputting the result. - Allow `\` at the end of a line. - Allow using `if` and `unless` inside macro expressions. - Allow marking a `fun/def` as `@[Raises]` (useful when a function can potentially raise from a callback). - Allow procs are now considered `@[Raises]`. - `OAuth2::Client` supports getting an access token via authorization code or refresh token. - Consecutive string literals are automatically concatenated by the parser as long as there is a `\` with a newline between them. - Many bug fixes. ### 0.5.1 (2014-10-16) - Added [json_mapping](https://github.com/crystal-lang/crystal/blob/master/spec/std/json/mapping_spec.cr) macro. - Added [Signal](https://github.com/crystal-lang/crystal/blob/master/src/signal.cr) module. - Added [Tempfile](https://github.com/crystal-lang/crystal/blob/master/src/tempfile.cr) class. - Enhanced [HTTP::Client](https://github.com/crystal-lang/crystal/blob/master/src/net/http/client/client.cr). - Added [OAuth::Consumer](https://github.com/crystal-lang/crystal/blob/master/libs/oauth/consumer.cr). - Added [OAuth2::Client](https://github.com/crystal-lang/crystal/blob/master/libs/oauth2/client.cr). - Added [OpenSSL::HMAC](https://github.com/crystal-lang/crystal/blob/master/libs/openssl/hmac.cr). - Added [SecureRandom](https://github.com/crystal-lang/crystal/blob/master/src/secure_random.cr). - New syntax for array/hash-like classes. For example: `Set {1, 2, 3}` and `HTTP::Headers {"content-type": "text/plain"}`. These just create the type and use `<<` or `[]=`. - Optimized Json parsing performance. - Added a [CSV builder](https://github.com/crystal-lang/crystal/blob/0.5.1//src/csv.cr#L13). - XML reader can [parse from an IO](https://github.com/crystal-lang/crystal/blob/0.5.1//src/xml/reader.cr#L10). - Added `Dir::glob` and `Dir::Entries` (thanks @jhass) - Allow `ensure` as an expression suffix. - Fixed [#219](https://github.com/crystal-lang/crystal/issues/219): Proc type is not inferred when passing to library fun and the return type doesn't match. - Fixed [#224](https://github.com/crystal-lang/crystal/issues/224): Class#new doesn't pass a block. - Fixed [#225](https://github.com/crystal-lang/crystal/issues/225): ICE when comparing void to something. - Fixed [#227](https://github.com/crystal-lang/crystal/issues/227): Nested captured block looses scope and crashes compiler. - Fixed [#228](https://github.com/crystal-lang/crystal/issues/228): Macro expansion doesn't retain symbol escaping as needed. - Fixed [#229](https://github.com/crystal-lang/crystal/issues/229): Can't change block context if defined within module context. - Fixed [#230](https://github.com/crystal-lang/crystal/issues/230): Type interference breaks equality operator. - Fixed [#233](https://github.com/crystal-lang/crystal/issues/233): Incorrect `no block given` message with new. - Other bug fixes. ### 0.5.0 (2014-09-24) - String overhaul, and optimizations ### 0.4.5 (2014-09-24) - Define backtick (`) for command execution. - Allow string literals as keys in hash literals: `{"foo": "bar"} # :: Hash(String, String)` - Allow `ifdef` as a suffix. - Integer division by zero raises a `DivisionByZero` exception. - Link attributes are now only processed if a lib function is used. - Removed the `type Name : Type` syntax (use `type Name = Type` instead). - Removed the `lib Lib("libname"); end` syntax. Use `@[Link]` attribute instead. - Fixed some `require` issues. - String representation includes length. - Upgraded to LLVM 3.5. ### 0.4.4 (2014-09-17) - Fixed [#193](https://github.com/crystal-lang/crystal/issues/193): allow initializing an enum value with another's one. - The `record` macro is now variadic, so instead of `record Vec3, [x, y, z]` write `record Vec3, x, y, z`. - The `def_equals`, `def_hash` and `def_equals_and_hash` macros are now variadic. - The `property`, `getter` and `setter` macros are now variadic. - All String methods are now UTF-8 aware. - `String#length` returns the number of characters, while `String#bytesize` return the number of bytes (previously `length` returned the number of bytes and `bytesize` didn't exist). - `String#[](index)` now returns a `Char` instead of an `UInt8`, where index is counted in characters. There's also `String#byte_at(index)`. - Removed the `\x` escape sequence in char and string literals. Use `\u` instead. - `initialize` methods are now protected. - Added `IO#gets_to_end`. - Added backticks (`...`) and `%x(...)` for command execution. - Added `%r(...)` for regular expression literals. - Allow interpolations in regular expression literals. - Compiling with `--release` sets a `release` flag that you can test with `ifdef`. - Allow passing splats to C functions - A C type can now be declared like `type Name = Type` (`type Name : Type` will be deprecated). - Now a C struct/union type can be created with named arguments. - New attributes syntax: `@[Attr(...)`] instead of `@:Attr`. The old syntax will be deprecated in a future release. - New link syntax for C libs: `@[Link("name")]` (uses `name` as `pkg-config name` if available or `-lname` instead), `@[Link(ldflags: "...")]` to pass raw flags to the linker, `@[Link("name", static: true)]` to try to find a static library first, and `@[Link(framework: "AppKit")]` (for Mac OSX). - Added an `exec` method to execute shell commands. Added the `system` and `backtick` similar to Ruby ones. - Added `be_truthy` and `be_falsey` spec matchers. Added `Array#zip` without a block. (thanks @mjgpy3) - Added `getter?` and `property?` macros to create methods that end with `?`. - Added a `CGI` module. - The compiler now only depends on `cc` for compiling (removed dependency to `llc`, `opt`, `llvm-dis` and `clang`). - Added `IO#tty?`. - Some bug fixes. ### 0.4.3 (2014-08-14) - Reverted a commit that introduced random crashes. ### 0.4.2 (2014-08-13) - Fixed [#187](https://github.com/crystal-lang/crystal/issues/185): mixing `yield` and `block.call` crashes the compiler. - Added `\u` unicode escape sequences inside strings and chars (similar to Ruby). `\x` will be deprecated as it can generate strings with invalid UTF-8 byte sequences. - Added `String#chars`. - Fixed: splats weren't working in `initialize`. - Added the `private` and `protected` visibility modifiers, with the same semantics as Ruby. The difference is that you must place them before a `def` or a macro call. - Some bug fixes. ### 0.4.1 (2014-08-09) - Fixed [#185](https://github.com/crystal-lang/crystal/issues/185): `-e` flag stopped working. - Added a `@length` compile-time variable available inside tuples that allows to do loop unrolling. - Some bug fixes. ### 0.4.0 (2014-08-08) - Support splats in macros. - Support splats in defs and calls. - Added named arguments. - Renamed the `make_named_tuple` macro to `record`. - Added `def_equals`, `def_hash` and `def_equals_and_hash` macros to generate them from a list of fields. - Added `Slice(T)`, which is a struct having a pointer and a length. Use this in IO for a safe API. - Some `StaticArray` fixes and enhancements. ### 0.3.5 (2014-07-29) - **(breaking change)** Removed the special `->` operator for pointers of structs/unions: instead of `foo->bar` use `foo.value.bar`; instead of `foo->bar = 1` use `foo.value.bar = 1`. - Added `colorize` file that provides methods to easily output bash colors. - Now you can use modules as generic type arguments (for example, do `x = [] of IO`). - Added SSL sockets. Now HTTP::Server implements HTTPS. - Macros have access to constants and types. - Allow iterating a range in macros with `for`. - Use cpu cycle counter to initialize random. - `method_missing` now works in generic types. - Fixed [#154](https://github.com/crystal-lang/crystal/issues/154): bug, constants are initialized before global variables. - Fixed [#168](https://github.com/crystal-lang/crystal/issues/168): incorrect type inference of instance variables if not assigned in superclass. - Fixed [#169](https://github.com/crystal-lang/crystal/issues/169): `responds_to?` wasn't working with generic types. - Fixed [#171](https://github.com/crystal-lang/crystal/issues/171): ensure blocks are not executed if the rescue block returns from a def. - Fixed [#175](https://github.com/crystal-lang/crystal/issues/175): invalid code generated when using with/yield with structs. - Fixed some parser issues and other small issues. - Allow forward struct/union declarations in libs. - Added `String#replace(Regex, String)` - Added a `Box(T)` class, useful for boxing value types to pass them to C as `Void*`. ### 0.3.4 (2014-07-21) - Fixed [#165](https://github.com/crystal-lang/crystal/issues/165): restrictions with generic types didn't work for hierarchy types. - Allow using a single underscore in restrictions, useful for matching against an n-tuple or an n-function where you don't care about the types (e.g.: `def foo(x : {_, _})`. - Added a `generate_hash` macro that generates a `hash` methods based on some AST nodes. - Added very basic `previous_def`: similar to `super`, but uses the previous definition of a method. Useful to decorate existing methods (similar to `alias_method_chain`). For now the method's type restrictions must match for a previous definition to be found. - Made the compiler a bit faster - Added `env` in macros, to fetch an environment value. Returns a StringLiteral if found or NilLiteral if not. - Make `return 1, 2` be the same as `return {1, 2}`. Same goes with `break` and `next`. - Added `Pointer#as_enumerable(size : Int)` to create an `Enumerable` from a Pointer with an associated size, with zero overhead. Some methods removed from `Pointer`: `each`, `map`, `to_a`, `index`. - Added `StaticArray::new`, `StaticArray::new(value)`, `StaticArray::new(&block)`, `StaticArray#shuffle!` and `StaticArray#map!`. - Faster `Char#to_s(io : IO)` ### 0.3.3 (2014-07-14) - Allow implicit conversion to C types by defining a `to_unsafe` method. This removed the hardcoded rule for converting a `String` to `UInt8*` and also allows passing an `Array(T)` to an argument expecting `Pointer(T)`. - Fixed `.is_a?(Class)` not working ([#162](https://github.com/crystal-lang/crystal/issues/162)) - Attributes are now associated to AST nodes in the semantic pass, not during parsing. This allows macros to generate attributes that will be attached to subsequent expressions. - **(breaking change)** Make ENV#[] raise on missing key, and added ENV#[]? - **(breaking change)** Macro defs are now written like `macro def name(args) : ReturnType` instead of `def name(args) : ReturnType`, which was a bit confusing. ### 0.3.2 (2014-07-10) - Integer literals without a suffix are inferred to be Int32, Int64 or UInt64 depending on their value. - Check that integer literals fit into their types. - Put back `Int#to_s(radix : Int)` (was renamed to `to_s_in_base` in the previous release) by also specifying a restriction in `Int#to_s(io : IO)`. - Added `expect_raises` macros in specs ### 0.3.1 (2014-07-09) - **(breaking change)** Replaced `@name` inside macros with `@class_name`. - **(breaking change)** Instance variables inside macros now don't have the `@` symbols in their names. ### 0.3.0 (2014-07-08) - Added `Array#each_index` - Optimized `String#*` for the case when the string has length one. - Use `GC.malloc_atomic` for String and String::Buffer (as they don't contain internal pointers.) - Added a `PointerAppender` struct to easily append to a `Pointer` while counting at the same time (thanks @kostya for the idea). - Added a `Base64` module (thanks @kostya) - Allow default arguments in macros - Allow invoking `new` on a function type. For example: `alias F = Int32 -> Int32; f = F.new { |x| x + 1 }; f.call(2) #=> 3`. - Allow omitting function argument types when invoking C functions that accept functions as arguments. - Renamed `@name` to `@class_name` inside macros. `@name` will be deprecated in the next version. - Added IO#read_fully - Macro hooks: `inherited`, `included` and `extended` - `method_missing` macro - Added `{{ raise ... }}` inside macros to issue a compile error. - Started JSON serialization and deserialization - Now `at_exit` handlers are run when you invoke `exit` - Methods can be marked as abstract - New convention for `to_s` and `inspect`: you must override them receiving an IO object - StringBuilder and StringBuffer have been replaced by StringIO ### 0.2.0 (2014-06-24) - Removed icr (a REPL): it is abandoned for the moment because it was done in a hacky, non-reliable way - Added very basic `String#underscore` and `String#camelcase`. - The parser generates string literals out of strings with interpolated string literals. For example, `"#{__DIR__}/foo"` is interpolated at compile time and generates a string literal with the full path, since `__DIR__` is just a (special) string literal. - **(breaking change)** Now macro nodes are always pasted as is. If you want to generate an id use `{{var.id}}`. Previously, a code like this: ```ruby macro foo(name) def {{name}}; end end foo :hello foo "hello" foo hello ``` generated this: ```ruby def hello; end def hello; end def hello; end ``` With this change, it generates this: ```ruby def :hello; end def "hello"; end def hello; end ``` Now, to get an identifier out of a symbol literal, string literal or a name, use id: ```ruby macro foo(name) def {{name.id}}; end end ``` Although it's longer to type, the implicit "id" call was sometimes confusing. Explicit is better than implicit. Invoking `id` on any other kind of node has no effect on the pasted result. - Allow escaping curly braces inside macros with `\{`. This allows defining macros that, when expanded, can contain other macro expressions. - Added a special comment-like pragma to change the lexer's filename, line number and column number. ```ruby # foo.cr a = 1 #b = 2 c = 3 ``` In the previous example, `b = 2` (and the rest of the file) is considered as being parsed from file `bar.cr` at line 12, column 24. - Added a special `run` call inside macros. This compiles and executes another Crystal program and pastes its output into the current program. As an example, consider this program: ```ruby # foo.cr {{ run("my_program", 1, 2, 3) }} ``` Compiling `foo.cr` will, at compile-time, compile `my_program.cr` and execute it with arguments `1 2 3`. The output of that execution is pasted into `foo.cr` at that location. - Added ECR (Embedded Crystal) support. This is implemented using the special `run` macro call. A small example: ```ruby # template.ecr Hello <%= @msg %> ``` ```ruby # foo.cr require "ecr/macros" class HelloView def initialize(@msg) end # This generates a to_s method with the contents of template.ecr ecr_file "template.ecr" end view = HelloView.new "world!" view.to_s #=> "Hello world!" ``` The nice thing about this is that, using the `#` pragma for specifying the lexer's location, if you have a syntax/semantic error in the template the error points to the template :-) ### 0.1.0 (2014-06-18) - First official release ================================================ FILE: doc/changelogs/v1.0.md ================================================ # Changelog 1.0 ## [1.0.0] - 2021-03-22 [1.0.0]: https://github.com/crystal-lang/crystal/releases/1.0.0 ### Language changes - Support `Tuple#[](Range)` with compile-time range literals. ([#10379](https://github.com/crystal-lang/crystal/pull/10379), thanks @HertzDevil) #### Macros - Don't use named argument key names as parameters for `method_missing` calls. ([#10388](https://github.com/crystal-lang/crystal/pull/10388), thanks @HertzDevil) ### Standard library - **(breaking-change)** Drop deprecated definitions. ([#10386](https://github.com/crystal-lang/crystal/pull/10386), thanks @bcardiff) - Fix example codes in multiple places. ([#10505](https://github.com/crystal-lang/crystal/pull/10505), thanks @maiha) #### Macros - **(breaking-change)** Always add explicit return types in getter/property macros. ([#10405](https://github.com/crystal-lang/crystal/pull/10405), thanks @Sija) #### Numeric - **(breaking-change)** Change default rounding mode to `TIES_EVEN`. ([#10508](https://github.com/crystal-lang/crystal/pull/10508), thanks @straight-shoota) - Fix downcasting float infinity. ([#10420](https://github.com/crystal-lang/crystal/pull/10420), thanks @straight-shoota) - Fix `String#to_f` out of range behaviour. ([#10425](https://github.com/crystal-lang/crystal/pull/10425), thanks @straight-shoota) - Implement rounding mode for `Number#round`. ([#10413](https://github.com/crystal-lang/crystal/pull/10413), [#10360](https://github.com/crystal-lang/crystal/pull/10360), [#10479](https://github.com/crystal-lang/crystal/pull/10479), thanks @straight-shoota) #### Text - Add missing unicode whitespace support to `String` methods. ([#10367](https://github.com/crystal-lang/crystal/pull/10367), thanks @straight-shoota) #### Collections - Fix `Range#==` to ignore generic type arguments. ([#10309](https://github.com/crystal-lang/crystal/pull/10309), thanks @straight-shoota) - Make `Enumerable#flat_map`, `Iterator#flat_map` work with mixed element types. ([#10329](https://github.com/crystal-lang/crystal/pull/10329), thanks @HertzDevil) - Remove duplicated `sort` related specs. ([#10208](https://github.com/crystal-lang/crystal/pull/10208), thanks @MakeNowJust) - Fix docs regarding `Set#each` return type. ([#10477](https://github.com/crystal-lang/crystal/pull/10477), thanks @kachick) - Fix docs examples regarding `Set#*set_of?`. ([#10285](https://github.com/crystal-lang/crystal/pull/10285), thanks @oddp) - Fix expectation on set specs. ([#10482](https://github.com/crystal-lang/crystal/pull/10482), thanks @kachick) #### Serialization - **(breaking-change)** Serialize `Enum` to underscored `String` by default. ([#10431](https://github.com/crystal-lang/crystal/pull/10431), thanks @straight-shoota, @caspiano) - **(breaking-change)** Use class instead of struct for types in XML module. ([#10436](https://github.com/crystal-lang/crystal/pull/10436), thanks @hugopl) - Add `YAML::Nodes::Node#kind`. ([#10432](https://github.com/crystal-lang/crystal/pull/10432), thanks @straight-shoota) #### Files - Let `IO::Memory` not be writable with read-only `Slice`. ([#10391](https://github.com/crystal-lang/crystal/pull/10391), thanks @straight-shoota) - Allow `Int64` values within `IO#read_at`. ([#10356](https://github.com/crystal-lang/crystal/pull/10356), thanks @Blacksmoke16) - Add `IO::Sized#remaining=(value)` to reuse an existing instance. ([#10520](https://github.com/crystal-lang/crystal/pull/10520), thanks @jgaskins) #### Networking - **(security)** Remove Cookie Name Decoding. ([#10442](https://github.com/crystal-lang/crystal/pull/10442), thanks @security-curious) - **(breaking-change)** Remove implicit en-/decoding for cookie values. ([#10485](https://github.com/crystal-lang/crystal/pull/10485), thanks @straight-shoota) - **(breaking-change)** Split `HTTP::Cookies.from_headers` into separate methods for server/client. ([#10486](https://github.com/crystal-lang/crystal/pull/10486), thanks @straight-shoota) - **(performance)** Minor performance improvements to `HTTP::Cookies`. ([#10488](https://github.com/crystal-lang/crystal/pull/10488), thanks @straight-shoota) - Respect subclasses when constructing `HTTP::Client` from class methods. ([#10375](https://github.com/crystal-lang/crystal/pull/10375), thanks @oprypin) - Make the `content-length` header more RFC compliant. ([#10353](https://github.com/crystal-lang/crystal/pull/10353), thanks @Blacksmoke16) - Fix `#respond_with_status` when headers written or closed. ([#10415](https://github.com/crystal-lang/crystal/pull/10415), thanks @straight-shoota) - Fix `Cookie#==` to take all ivars into account. ([#10487](https://github.com/crystal-lang/crystal/pull/10487), thanks @straight-shoota) - Remove implicit `path=/` from `HTTP::Cookie`. ([#10491](https://github.com/crystal-lang/crystal/pull/10491), thanks @straight-shoota) - Add `HTTP::Request#local_address`. ([#10385](https://github.com/crystal-lang/crystal/pull/10385), thanks @carlhoerberg) #### Logging - Close `AsyncDispatcher` on `#finalize`. ([#10390](https://github.com/crystal-lang/crystal/pull/10390), thanks @straight-shoota) #### System - Fix `Process.parse_argument` behavior against a quote in a word. ([#10337](https://github.com/crystal-lang/crystal/pull/10337), thanks @MakeNowJust) - Add aarch64 support for macOS/darwin targets. ([#10348](https://github.com/crystal-lang/crystal/pull/10348), thanks @maxfierke, @RomainFranceschini) - Add `LibC::MAP_ANONYMOUS` to x86_64-darwin to match other platforms. ([#10398](https://github.com/crystal-lang/crystal/pull/10398), thanks @sourgrasses) #### Runtime - Improve error message for ELF reader on uninitialized runtime. ([#10282](https://github.com/crystal-lang/crystal/pull/10282), thanks @straight-shoota) ### Compiler - **(breaking-change)** Disallow surrogate halves in escape sequences of string and character literals, use `\x` for arbitrary binary values. ([#10443](https://github.com/crystal-lang/crystal/pull/10443), thanks @HertzDevil) - Fix ICE when exhaustive in-clause calls pseudo-method. ([#10382](https://github.com/crystal-lang/crystal/pull/10382), thanks @HertzDevil) - Fix ICE when parsing `foo.%` calls. ([#10351](https://github.com/crystal-lang/crystal/pull/10351), thanks @MakeNowJust) - Fix edge cases for symbol quoting rules. ([#10389](https://github.com/crystal-lang/crystal/pull/10389), thanks @HertzDevil) - Support closured vars inside `Const` initializer. ([#10478](https://github.com/crystal-lang/crystal/pull/10478), thanks @RX14) - Documentation grammar fix. ([#10369](https://github.com/crystal-lang/crystal/pull/10369), thanks @szTheory) #### Language semantics - Don't fail on untyped `is_a?`. ([#10320](https://github.com/crystal-lang/crystal/pull/10320), thanks @asterite) - Fix named arguments in `super` and `previous_def` calls. ([#10400](https://github.com/crystal-lang/crystal/pull/10400), thanks @HertzDevil) - Fix assignments in array literals. ([#10009](https://github.com/crystal-lang/crystal/pull/10009), thanks @straight-shoota) - Consider type var splats in generic type restrictions. ([#10168](https://github.com/crystal-lang/crystal/pull/10168), thanks @HertzDevil) - Align `Proc.new(&block)`'s behaviour with other captured blocks. ([#10263](https://github.com/crystal-lang/crystal/pull/10263), thanks @HertzDevil) - Don't merge `NamedTuple` metaclasses through instance types. ([#10501](https://github.com/crystal-lang/crystal/pull/10501), thanks @HertzDevil) - Access instantiations of `NamedTuple` and other generics uniformly. ([#10401](https://github.com/crystal-lang/crystal/pull/10401), thanks @HertzDevil) - Improve error message for auto-cast error at Var assign. ([#10327](https://github.com/crystal-lang/crystal/pull/10327), thanks @straight-shoota) - Exclude abstract defs from "no overload matches" errors. ([#10483](https://github.com/crystal-lang/crystal/pull/10483), thanks @HertzDevil) - Support splats inside tuple literals in type names. ([#10430](https://github.com/crystal-lang/crystal/pull/10430), thanks @HertzDevil) - Accept pointer instance types on falsey conditional branches. ([#10464](https://github.com/crystal-lang/crystal/pull/10464), thanks @HertzDevil) - Match named arguments by external parameter names when checking overload cover. ([#10530](https://github.com/crystal-lang/crystal/pull/10530), thanks @HertzDevil) #### Doc generator - Detect source locations in more situations. ([#10439](https://github.com/crystal-lang/crystal/pull/10439), thanks @oprypin) ### Others - CI improvements and housekeeping. ([#10299](https://github.com/crystal-lang/crystal/pull/10299), [#10340](https://github.com/crystal-lang/crystal/pull/10340), [#10476](https://github.com/crystal-lang/crystal/pull/10476), [#10480](https://github.com/crystal-lang/crystal/pull/10480), thanks @bcardiff, @Sija, @straight-shoota) - Update distribution-scripts to use Shards v0.14.1. ([#10494](https://github.com/crystal-lang/crystal/pull/10494), thanks @bcardiff) - Add GitHub issue templates. ([#8934](https://github.com/crystal-lang/crystal/pull/8934), thanks @j8r) - Add LLVM 11.1 to the list of supported versions. ([#10523](https://github.com/crystal-lang/crystal/pull/10523), thanks @Sija) - Fix SDL examples crashes. ([#10470](https://github.com/crystal-lang/crystal/pull/10470), thanks @megatux) ================================================ FILE: doc/changelogs/v1.1.md ================================================ # Changelog 1.1 ## [1.1.1] - 2021-07-26 [1.1.1]: https://github.com/crystal-lang/crystal/releases/1.1.1 ### Language changes - Revert name of top-level module to `main` ([#10993](https://github.com/crystal-lang/crystal/pull/10993), thanks @beta-ziliani) ### Standard Library - Fix missing required args for `Socket::Addrinfo::Error.new` ([#10960](https://github.com/crystal-lang/crystal/pull/10960), thanks @straight-shoota) - Fix disable unnecessary spec on win32 ([#10971](https://github.com/crystal-lang/crystal/pull/10971), thanks @straight-shoota) - Remove incorrect type restrictions on index methods with offset ([#10972](https://github.com/crystal-lang/crystal/pull/10972), thanks @straight-shoota) - Fix: documentation of `#step` in `Number` and `Char` ([#10966](https://github.com/crystal-lang/crystal/pull/10966), [#11006](https://github.com/crystal-lang/crystal/pull/11006), thanks @beta-ziliani and @straight-shoota) ### Compiler - Fix parsing macro body with escaped backslash in literal ([#10995](https://github.com/crystal-lang/crystal/pull/10995), thanks @straight-shoota) ### Other - Updating aarch64 actions to use 1.0.0 images ([#10976](https://github.com/crystal-lang/crystal/pull/10976), thanks @beta-ziliani) ## [1.1.0] - 2021-07-14 [1.1.0]: https://github.com/crystal-lang/crystal/releases/1.1.0 ### Language changes - Support splat expansions inside tuple and array literals. ([#10429](https://github.com/crystal-lang/crystal/pull/10429), thanks @HertzDevil) - Support breaks with values inside `while` expressions. ([#10566](https://github.com/crystal-lang/crystal/pull/10566), thanks @HertzDevil) #### Macros - Add `@top_level` to access the top-level scope in macros. ([#10682](https://github.com/crystal-lang/crystal/pull/10682), thanks @beta-ziliani) - Fix: preserve integer sizes in `NumberLiteral#int_bin_op`. ([#10713](https://github.com/crystal-lang/crystal/pull/10713), thanks @collidedscope) - Add `NumberLiteral#to_number`. ([#10802](https://github.com/crystal-lang/crystal/pull/10802), thanks @straight-shoota) - **(breaking-change)** Add `Crystal::Macros::Path#global?` deprecating the old `Crystal::Macros::Path#global`. ([#10812](https://github.com/crystal-lang/crystal/pull/10812), thanks @HertzDevil) - Minor fixes to docs of `UnaryExpression` macro nodes. ([#10816](https://github.com/crystal-lang/crystal/pull/10816), thanks @HertzDevil) - Add macro method `ASTNode#nil?`. ([#10850](https://github.com/crystal-lang/crystal/pull/10850), [#10616](https://github.com/crystal-lang/crystal/pull/10616), thanks @straight-shoota) ### Standard library #### Global changes ##### Windows support - Port `Socket::Address` to win32 . ([#10610](https://github.com/crystal-lang/crystal/pull/10610), thanks @straight-shoota) - Port `Socket::Addrinfo` to win32. ([#10650](https://github.com/crystal-lang/crystal/pull/10650), thanks @straight-shoota) - Extract system-specifics from Socket. ([#10706](https://github.com/crystal-lang/crystal/pull/10706), thanks @straight-shoota) - Make `WinError` portable and add it to prelude. ([#10725](https://github.com/crystal-lang/crystal/pull/10725), thanks @straight-shoota) - Improve portability of `SystemError`. ([#10726](https://github.com/crystal-lang/crystal/pull/10726), thanks @straight-shoota) - Refactor `Socket::Addrinfo::Error` based on `os_error`. ([#10761](https://github.com/crystal-lang/crystal/pull/10761), thanks @straight-shoota) - Add `WinError.wsa_value` and specs for `WinError`. ([#10762](https://github.com/crystal-lang/crystal/pull/10762), thanks @straight-shoota) - Add specs for `Errno`. ([#10763](https://github.com/crystal-lang/crystal/pull/10763), thanks @straight-shoota) - Refactor: Move win32 libc bindings from `winbase.cr` to appropriate files. ([#10771](https://github.com/crystal-lang/crystal/pull/10771), thanks @straight-shoota) - Refactor: Change protocol socket fd to `Socket::Handle`. ([#10772](https://github.com/crystal-lang/crystal/pull/10772), thanks @straight-shoota) - Fix `Socket::Connect` error in addrinfo inherit `os_error`. ([#10782](https://github.com/crystal-lang/crystal/pull/10782), thanks @straight-shoota) - Reorganize some win32 libc bindings ([#10776](https://github.com/crystal-lang/crystal/pull/10776), thanks @straight-shoota) ##### Type annotations - Add type restriction to private `Process` constructor. ([#7040](https://github.com/crystal-lang/crystal/pull/7040), thanks @z64) - Add various return type restrictions (thanks @oprypin, @straight-shoota, and @caspiano): [#10578](https://github.com/crystal-lang/crystal/pull/10578), [#10579](https://github.com/crystal-lang/crystal/pull/10579), [#10580](https://github.com/crystal-lang/crystal/pull/10580), [#10581](https://github.com/crystal-lang/crystal/pull/10581), [#10582](https://github.com/crystal-lang/crystal/pull/10582), [#10583](https://github.com/crystal-lang/crystal/pull/10583), [#10584](https://github.com/crystal-lang/crystal/pull/10584), [#10585](https://github.com/crystal-lang/crystal/pull/10585), [#10586](https://github.com/crystal-lang/crystal/pull/10586), [#10587](https://github.com/crystal-lang/crystal/pull/10587), [#10588](https://github.com/crystal-lang/crystal/pull/10588), [#10849](https://github.com/crystal-lang/crystal/pull/10849), [#10856](https://github.com/crystal-lang/crystal/pull/10856), [#10857](https://github.com/crystal-lang/crystal/pull/10857), [#10858](https://github.com/crystal-lang/crystal/pull/10858), [#10905](https://github.com/crystal-lang/crystal/pull/10905) - Add type restrictions for splat-less overloads of some methods. ([#10594](https://github.com/crystal-lang/crystal/pull/10594), thanks @HertzDevil) #### Numeric - Add `Number.new` overload for `String`. ([#10422](https://github.com/crystal-lang/crystal/pull/10422), thanks @Blacksmoke16) - Fix `Math.pw2ceil` for zero and 64-bit integers. ([#10555](https://github.com/crystal-lang/crystal/pull/10555), thanks @straight-shoota) - Add `#positive?` & `#negative?` to `Number` and `Time::Span`. ([#10601](https://github.com/crystal-lang/crystal/pull/10601), thanks @Blacksmoke16) - Fix imprecise `Number#significant` algorithm. ([#10615](https://github.com/crystal-lang/crystal/pull/10615), thanks @straight-shoota) - Add `BigFloat`'s rounding modes. ([#10618](https://github.com/crystal-lang/crystal/pull/10618), thanks @HertzDevil) - Fix handling of arithmetic overflow in `BigDecimal#div`. ([#10628](https://github.com/crystal-lang/crystal/pull/10628), thanks @kellydanma) - Clarify behaviour of unsafe `Float`-to-number conversions. ([#10631](https://github.com/crystal-lang/crystal/pull/10631), thanks @HertzDevil) - Fix return type restriction for `Number#humanize` overload. ([#10633](https://github.com/crystal-lang/crystal/pull/10633), thanks @HertzDevil) - Fix `printf` float with many digits. ([#10719](https://github.com/crystal-lang/crystal/pull/10719), thanks @straight-shoota) - Add `BigDecimal`'s missing rounding modes. ([#10798](https://github.com/crystal-lang/crystal/pull/10798), thanks @HertzDevil) - Add support for using big rational `#**` with unsigned ints. ([#10887](https://github.com/crystal-lang/crystal/pull/10887), thanks @stakach) - Add overflow detection to `BigFloat#to_i64` and `#to_u64`. ([#10630](https://github.com/crystal-lang/crystal/pull/10630), thanks @HertzDevil) #### Text - **(performance)** Optimize `Levenshtein.distance`. ([#8324](https://github.com/crystal-lang/crystal/pull/8324), thanks @r00ster91) - Refactor: add private `Slice#hexdump(io : IO)` overload. ([#10496](https://github.com/crystal-lang/crystal/pull/10496), thanks @HertzDevil) - Restrict `MatchData#begin` and `#end` to `Int32`. ([#10656](https://github.com/crystal-lang/crystal/pull/10656), thanks @straight-shoota) - Refactor: remove `#check_needs_resize` from `IO::Memory`, `String::Builder`. ([#10732](https://github.com/crystal-lang/crystal/pull/10732), thanks @straight-shoota) - Fix `Base64#encode`, exclude last 3 bytes from bswap. ([#10752](https://github.com/crystal-lang/crystal/pull/10752), thanks @kostya) - Refactor: avoid union type in `Char::Reader#decode_char_at`. ([#10758](https://github.com/crystal-lang/crystal/pull/10758), thanks @asterite) #### Collections - Add sub/superset checking methods to `Hash`. ([#7500](https://github.com/crystal-lang/crystal/pull/7500), thanks @Sija) - Improve documentation of `Array#[](Range)`. ([#10243](https://github.com/crystal-lang/crystal/pull/10243), thanks @straight-shoota) - Add `Steppable` module as generalized `Number#step`. ([#10279](https://github.com/crystal-lang/crystal/pull/10279), thanks @straight-shoota) - Add docs for `#map_with_index`. ([#10512](https://github.com/crystal-lang/crystal/pull/10512), thanks @wontruefree) - Add `Array#truncate`. ([#10712](https://github.com/crystal-lang/crystal/pull/10712), thanks @HertzDevil) - Fix: Always copy `Hash`'s default block on `#dup` and `#clone`. ([#10744](https://github.com/crystal-lang/crystal/pull/10744), thanks @HertzDevil) - Apply `Array#push`'s resizing heuristic to `#unshift`. ([#10750](https://github.com/crystal-lang/crystal/pull/10750), thanks @HertzDevil) - Refactor index / count normalization in range-like methods. ([#10753](https://github.com/crystal-lang/crystal/pull/10753), thanks @HertzDevil) - Add methods for cumulative folding and prefix sums. ([#10789](https://github.com/crystal-lang/crystal/pull/10789), thanks @HertzDevil) - Fix: Pass read-only flag to peeked slice in `IO::Memory`. ([#10891](https://github.com/crystal-lang/crystal/pull/10891), thanks @z64) #### Crypto - Add methods for getting peer certificates and signatures in `OpenSSL`. ([#8005](https://github.com/crystal-lang/crystal/pull/8005), thanks @will) - Add docs for `OpenSSL::Cipher`. ([#9934](https://github.com/crystal-lang/crystal/pull/9934), thanks @sol-vin) - Fix format of `src/openssl/cipher.cr`. ([#10705](https://github.com/crystal-lang/crystal/pull/10705), thanks @straight-shoota) - Refine documentation for `Random#urlsafe_base64`. ([#10724](https://github.com/crystal-lang/crystal/pull/10724), thanks @straight-shoota) - Fix ssl context required for `add_x509_verify_flags`. ([#10756](https://github.com/crystal-lang/crystal/pull/10756), thanks @stakach) #### Time - Improve error handling for `load_localtime` on unix. ([#10654](https://github.com/crystal-lang/crystal/pull/10654), thanks @straight-shoota) - Fix broken call to `Time#to_s`. ([#10778](https://github.com/crystal-lang/crystal/pull/10778), thanks @straight-shoota) - Fix `Time#shift` cover date boundaries with zone offset. ([#10871](https://github.com/crystal-lang/crystal/pull/10871), thanks @straight-shoota) #### Files - Fix and unify documentation for `puts`. ([#10614](https://github.com/crystal-lang/crystal/pull/10614), thanks @straight-shoota) - Fix `Path#sibling` return type. ([#10655](https://github.com/crystal-lang/crystal/pull/10655), thanks @Sija) - Add `Path` in `FileUtils`'s methods to match the interfaces it's wrapping. ([#10747](https://github.com/crystal-lang/crystal/pull/10747), thanks @yb66) - Fix `FileDescriptor#pos` return `Int64` on armv6 ([#10845](https://github.com/crystal-lang/crystal/pull/10845), thanks @straight-shoota) #### Fibers - Clarify documentation on `Path#join` and `#==`. ([#10455](https://github.com/crystal-lang/crystal/pull/10455), thanks @straight-shoota) #### Networking - Add an example middleware for `remote_address`. ([#10408](https://github.com/crystal-lang/crystal/pull/10408), thanks @oprypin) - Add `OAuth2::Client#http_client`. ([#10452](https://github.com/crystal-lang/crystal/pull/10452), thanks @straight-shoota) - Fix undefined constant error for `http/params`. ([#10537](https://github.com/crystal-lang/crystal/pull/10537), thanks @stakach) - Fix looping forever at 100% CPU if socket is closed. ([#10658](https://github.com/crystal-lang/crystal/pull/10658), thanks @didactic-drunk) - Fix documentation of `HTTP::Cookies#[]=` empty path. ([#10669](https://github.com/crystal-lang/crystal/pull/10669), thanks @straight-shoota) - Fix handling of `EAI_SYSTEM` for `getaddrinfo`. ([#10757](https://github.com/crystal-lang/crystal/pull/10757), thanks @straight-shoota) - **(performance)** Cache `socket.local_address` and `socket.remote_address`. ([#10765](https://github.com/crystal-lang/crystal/pull/10765), thanks @lbguilherme) - Fix: `IO::ARGF#read` should always return `i32`. ([#10828](https://github.com/crystal-lang/crystal/pull/10828), thanks @stakach) - Fix `HTTP::Cookie` parse quoted cookie value. ([#10853](https://github.com/crystal-lang/crystal/pull/10853), thanks @straight-shoota) - Add `Socket::Addrinfo#inspect` ([#10775](https://github.com/crystal-lang/crystal/pull/10775), thanks @straight-shoota) #### System - Fix sentence structure in `process.cr`. ([#9259](https://github.com/crystal-lang/crystal/pull/9259), thanks @matthewmcgarvey) #### Runtime - Implement segfault handler in Crystal. ([#10463](https://github.com/crystal-lang/crystal/pull/10463), thanks @maxfierke) - Improve documentation for `Pointer.malloc` and `GC` methods. ([#10644](https://github.com/crystal-lang/crystal/pull/10644), thanks @straight-shoota) - Add links to literal types in the language reference. ([#10827](https://github.com/crystal-lang/crystal/pull/10827), thanks @straight-shoota) #### Serialization - Add docs for some json methods. ([#10257](https://github.com/crystal-lang/crystal/pull/10257), thanks @rdp) - Add `UUID.from_json_object_key?`. ([#10517](https://github.com/crystal-lang/crystal/pull/10517), thanks @kalinon) - Fix `JSON::Lexer`'s UTF-16 escape sequence parsing. ([#10450](https://github.com/crystal-lang/crystal/pull/10450), thanks @HertzDevil) - Fix `YAML::Serializable.use_yaml_discriminator` with typed enum. ([#10460](https://github.com/crystal-lang/crystal/pull/10460), thanks @straight-shoota) - Fix YAML to not parse empty string as `nil`. ([#10608](https://github.com/crystal-lang/crystal/pull/10608), thanks @straight-shoota) - Add `UUID` to yaml parsing. ([#10715](https://github.com/crystal-lang/crystal/pull/10715), thanks @kalinon) - Fix double flushing json/yaml builders. ([#10716](https://github.com/crystal-lang/crystal/pull/10716), thanks @matthewmcgarvey) #### Specs - Add spec helper `it_iterates` for iteration methods. ([#10158](https://github.com/crystal-lang/crystal/pull/10158), [#10797](https://github.com/crystal-lang/crystal/pull/10797), thanks @straight-shoota) - Add usage instructions for spec runner to compiler. ([#10046](https://github.com/crystal-lang/crystal/pull/10046), thanks @straight-shoota) - Fix: Handle invalid option errors on `crystal spec`. ([#10787](https://github.com/crystal-lang/crystal/pull/10787), thanks @hugopl) - Include `spec/**` in docs_main. ([#10863](https://github.com/crystal-lang/crystal/pull/10863), thanks @straight-shoota) ### Compiler - Add support for type var splats inside `Tuple` during generic parameter substitution. ([#10232](https://github.com/crystal-lang/crystal/pull/10232), thanks @HertzDevil) - Fix: consider free vars in parameters of abstract def implementations before existing types, in particular fixing the creation of empty types. ([#10503](https://github.com/crystal-lang/crystal/pull/10503), thanks @HertzDevil) - Replace `Crystal::Type#covariant?` with `#implements?` ([#10507](https://github.com/crystal-lang/crystal/pull/10507), thanks @HertzDevil) - Fix error message when default parameter value doesn't match non-type restriction. ([#10515](https://github.com/crystal-lang/crystal/pull/10515), thanks @HertzDevil) - Fix type restriction logic for generic module instances. ([#10519](https://github.com/crystal-lang/crystal/pull/10519), thanks @HertzDevil) - Fix logic for subclass restricted against uninstantiated nested generic superclass. ([#10522](https://github.com/crystal-lang/crystal/pull/10522), [#10560](https://github.com/crystal-lang/crystal/pull/10560), thanks @HertzDevil) - Fix: eliminate extraneous types in certain non-commutative unions. ([#10527](https://github.com/crystal-lang/crystal/pull/10527), thanks @HertzDevil) - Fix: exclude variables' final types inside `while true` if re-assigned before first break. ([#10538](https://github.com/crystal-lang/crystal/pull/10538), thanks @HertzDevil) - Make `Pointer(T)#value=` even stricter for generic arguments. ([#10553](https://github.com/crystal-lang/crystal/pull/10553), thanks @HertzDevil) - Fix body locations for def nodes that have default args . ([#10619](https://github.com/crystal-lang/crystal/pull/10619), thanks @oprypin) - Fix call nodes' location after transforming its splats. ([#10620](https://github.com/crystal-lang/crystal/pull/10620), thanks @oprypin) - Fix `check_type_allowed_as_proc_argument` to show the type name. ([#10688](https://github.com/crystal-lang/crystal/pull/10688), thanks @straight-shoota) - Add free variables to "no overload matches" errors. ([#10692](https://github.com/crystal-lang/crystal/pull/10692), thanks @HertzDevil) - Fix: make virtual unbound types also unbound. ([#10704](https://github.com/crystal-lang/crystal/pull/10704), thanks @HertzDevil) - Fix: run instance variable initializers on instantiated generic superclasses only. ([#10729](https://github.com/crystal-lang/crystal/pull/10729), thanks @HertzDevil) - Fix: allow `previous_def` to init superclass's non-nilable ivars. ([#10733](https://github.com/crystal-lang/crystal/pull/10733), thanks @HertzDevil) - Fix: Use only last sub-expression of `Expressions` nodes for conditional type filters. ([#10738](https://github.com/crystal-lang/crystal/pull/10738), thanks @HertzDevil) - Fix: Don't compute type filters inside `typeof`'s argument. ([#10739](https://github.com/crystal-lang/crystal/pull/10739), thanks @HertzDevil) - Fix: Devirtualize types in `TypeNode#==(other : TypeNode)` and `#!=`. ([#10742](https://github.com/crystal-lang/crystal/pull/10742), thanks @HertzDevil) - Fix exit types of variables assigned inside `while` conditions. ([#10759](https://github.com/crystal-lang/crystal/pull/10759), thanks @HertzDevil) - Fix logic for `responds_to?` of generic module instances. ([#10760](https://github.com/crystal-lang/crystal/pull/10760), thanks @HertzDevil) - Add support for accessing a common value of a union type. ([#10770](https://github.com/crystal-lang/crystal/pull/10770), thanks @asterite) - Fix subtype relation when generic type variable is a virtual abstract struct. ([#10779](https://github.com/crystal-lang/crystal/pull/10779), thanks @HertzDevil) - Fix array literals consisting entirely of splat expansions. ([#10792](https://github.com/crystal-lang/crystal/pull/10792), thanks @HertzDevil) - Fix parsing macro literal containing char literal. ([#10799](https://github.com/crystal-lang/crystal/pull/10799), thanks @straight-shoota) - Refactor: Use type instead of `is_a?` in filters. ([#10815](https://github.com/crystal-lang/crystal/pull/10815), thanks @caspiano) - Expand named macro expression arguments before outer macro call expansion. ([#10819](https://github.com/crystal-lang/crystal/pull/10819), thanks @HertzDevil) - Be more strict about printing operator calls as short forms. ([#10825](https://github.com/crystal-lang/crystal/pull/10825), thanks @HertzDevil) - Fix union logic between metaclasses of uninstantiated generic classes in same hierarchy. ([#10832](https://github.com/crystal-lang/crystal/pull/10832), thanks @HertzDevil) - Fix uninstantiated generic classes casting to themselves. ([#10883](https://github.com/crystal-lang/crystal/pull/10883), thanks @HertzDevil) - Allow underscore in block return type even if the type can't be computed ([#10933](https://github.com/crystal-lang/crystal/pull/10933), thanks @asterite) - Fix parser identifies call with named args as var ([#10842](https://github.com/crystal-lang/crystal/pull/10842), thanks @straight-shoota) ### Tools #### Formatter - Fix: allow trailing space in parenthesized unions. ([#10595](https://github.com/crystal-lang/crystal/pull/10595), thanks @HertzDevil) - Fix: don't consume newline after endless range literals. ([#10596](https://github.com/crystal-lang/crystal/pull/10596), thanks @HertzDevil) - Fix indentation of heredocs relative to delimiter. ([#10806](https://github.com/crystal-lang/crystal/pull/10806), thanks @HertzDevil) - Fix heredoc indent with outer indent. ([#10867](https://github.com/crystal-lang/crystal/pull/10867), thanks @straight-shoota) #### Doc generator - Fix escaping of argument lists in doc generator, expose JSON. ([#10109](https://github.com/crystal-lang/crystal/pull/10109), [#10821](https://github.com/crystal-lang/crystal/pull/10821), thanks @oprypin and @Sija) - Print named generic type arguments of type restrictions in docs. ([#10424](https://github.com/crystal-lang/crystal/pull/10424), thanks @HertzDevil) - Fix: respect overload order between methods. ([#10609](https://github.com/crystal-lang/crystal/pull/10609), thanks @HertzDevil) - Fix `PropagateDocVisitor` visit macro def. ([#10634](https://github.com/crystal-lang/crystal/pull/10634), thanks @straight-shoota) - Fix: remove superclass from `ASTNode` in API docs. ([#10664](https://github.com/crystal-lang/crystal/pull/10664), thanks @beta-ziliani) - **(breaking-change)** Remove deprecated `ditto` doc directive. ([#10755](https://github.com/crystal-lang/crystal/pull/10755), thanks @caspiano) (Note that it was scheduled for removal since 0.34) - Fix: Restrict macro types' ancestors to `ASTNode`. ([#10722](https://github.com/crystal-lang/crystal/pull/10722), thanks @HertzDevil) - Fix docs generator search use `html_id`. ([#10875](https://github.com/crystal-lang/crystal/pull/10875), thanks @straight-shoota) - Fix `--sitemap-priority`, `--sitemap-changefreq`. ([#10906](https://github.com/crystal-lang/crystal/pull/10906), thanks @HertzDevil) ### Others - CI: Update to use 1.0.0. ([#10533](https://github.com/crystal-lang/crystal/pull/10533), thanks @bcardiff) - Bump distribution-scripts. ([#10639](https://github.com/crystal-lang/crystal/pull/10639), [#10673](https://github.com/crystal-lang/crystal/pull/10673), [#10754](https://github.com/crystal-lang/crystal/pull/10754), thanks @straight-shoota and @bcardiff) - Fix contribution instructions. ([#10558](https://github.com/crystal-lang/crystal/pull/10558), thanks @straight-shoota) - Remove `.dockerignore`. ([#10642](https://github.com/crystal-lang/crystal/pull/10642), thanks @miry) - Add section about pull requests to the contributing guide. ([#10683](https://github.com/crystal-lang/crystal/pull/10683), thanks @straight-shoota) - Publish nightly builds to OBS. ([#10684](https://github.com/crystal-lang/crystal/pull/10684), thanks @straight-shoota) - Remove broken travis.yml config from `crystal init`. ([#10800](https://github.com/crystal-lang/crystal/pull/10800), thanks @straight-shoota) - Disable broken `test_darwin` job on circleci. ([#10823](https://github.com/crystal-lang/crystal/pull/10823), thanks @straight-shoota) - Update distribution-scripts for shards 0.15.0. ([#10862](https://github.com/crystal-lang/crystal/pull/10862), thanks @straight-shoota) - Add smoke tests for platforms where we don't run full tests ([#10848](https://github.com/crystal-lang/crystal/pull/10848), thanks @straight-shoota) ================================================ FILE: doc/changelogs/v1.10.md ================================================ # Changelog 1.10 ## [1.10.1] (2023-10-13) [1.10.1]: https://github.com/crystal-lang/crystal/releases/1.10.1 ### Bugfixes #### stdlib - `IO#gets` should have same result regardless of `#peek` availability ([#13882](https://github.com/crystal-lang/crystal/pull/13882), thanks @compumike) - Support Android API levels 24 - 27 ([#13884](https://github.com/crystal-lang/crystal/pull/13884), thanks @HertzDevil) ### Infrastructure - _(ci)_ Fix `win.yml` ([#13876](https://github.com/crystal-lang/crystal/pull/13876), thanks @straight-shoota) ## [1.10.0] (2023-10-09) [1.10.0]: https://github.com/crystal-lang/crystal/releases/1.10.0 ### Features #### lang - Add unlimited block unpacking ([#11597](https://github.com/crystal-lang/crystal/pull/11597), thanks @asterite) #### stdlib - Add more `Colorize::Mode` flags ([#13745](https://github.com/crystal-lang/crystal/pull/13745), thanks @HertzDevil) - _(collection)_ Add `Hash#put_if_absent` ([#13590](https://github.com/crystal-lang/crystal/pull/13590), thanks @HertzDevil) - _(collection)_ Add `Set#rehash` ([#13630](https://github.com/crystal-lang/crystal/pull/13630), thanks @HertzDevil) - _(collection)_ Add yield `key` in `Hash#transform_values` and `value` in `#transform_keys` ([#13608](https://github.com/crystal-lang/crystal/pull/13608), thanks @baseballlover723) - _(crypto)_ Upgrade SSL defaults to Mozilla guidelines version 5.7 ([#13685](https://github.com/crystal-lang/crystal/pull/13685), thanks @straight-shoota) - _(crypto)_ **[security]** Allow OpenSSL clients to choose cipher ([#13695](https://github.com/crystal-lang/crystal/pull/13695), thanks @carlhoerberg) - _(files)_ Add `File#rename` ([#13640](https://github.com/crystal-lang/crystal/pull/13640), thanks @carlhoerberg) - _(llvm)_ Support LLVM 17 ([#13782](https://github.com/crystal-lang/crystal/pull/13782), thanks @HertzDevil) - _(networking)_ Add overloads for `URI::Params.encode` with `IO` parameter ([#13798](https://github.com/crystal-lang/crystal/pull/13798), thanks @jwoertink) - _(numeric)_ Add `Complex#to_i128`, `Complex#to_u128` ([#13838](https://github.com/crystal-lang/crystal/pull/13838), thanks @HertzDevil) - _(runtime)_ Add additional fields to `GC:ProfStats` ([#13734](https://github.com/crystal-lang/crystal/pull/13734), thanks @carlhoerberg) - _(serialization)_ Support YAML deserialization of 128-bit integers ([#13834](https://github.com/crystal-lang/crystal/pull/13834), thanks @HertzDevil) - _(serialization)_ Support 128-bit integers in `JSON::PullParser#read?` ([#13837](https://github.com/crystal-lang/crystal/pull/13837), thanks @HertzDevil) - _(specs)_ **[breaking]** Change spec runner to exit with failure for `focus: true` ([#13653](https://github.com/crystal-lang/crystal/pull/13653), thanks @straight-shoota) - _(text)_ Add `String#byte_index(Char)` ([#13819](https://github.com/crystal-lang/crystal/pull/13819), thanks @funny-falcon) - _(time)_ Support Android's system timezone database ([#13666](https://github.com/crystal-lang/crystal/pull/13666), thanks @HertzDevil) #### compiler - Experimental: Add `Slice.literal` for numeric slice constants ([#13716](https://github.com/crystal-lang/crystal/pull/13716), thanks @HertzDevil) #### tools - Add `tool unreachable` ([#13783](https://github.com/crystal-lang/crystal/pull/13783), thanks @straight-shoota) - _(dependencies)_ Add `crystal tool dependencies` ([#13631](https://github.com/crystal-lang/crystal/pull/13631), thanks @straight-shoota) - _(docs-generator)_ Add CSS for tables ([#13822](https://github.com/crystal-lang/crystal/pull/13822), thanks @nobodywasishere) - _(hierarchy)_ Support generic types in `crystal tool hierarchy` ([#13715](https://github.com/crystal-lang/crystal/pull/13715), thanks @HertzDevil) - _(playground)_ Update octicons to v19.5.0 ([#13738](https://github.com/crystal-lang/crystal/pull/13738), thanks @GeopJr) ### Bugfixes #### lang - _(macros)_ Fix missing normalization of macro expressions (and others) ([#13709](https://github.com/crystal-lang/crystal/pull/13709), thanks @asterite) - _(macros)_ Fix block parameter unpacking inside macros ([#13813](https://github.com/crystal-lang/crystal/pull/13813), thanks @HertzDevil) #### stdlib - _(collection)_ **[breaking]** Mark the return type of methods such as `Slice#copy_to` as `Nil` ([#13774](https://github.com/crystal-lang/crystal/pull/13774), thanks @erdian718) - _(files)_ Change `IO::Buffered#peek`'s return type to `Bytes` ([#13863](https://github.com/crystal-lang/crystal/pull/13863), thanks @HertzDevil) - _(llvm)_ Chop git suffix from `LibLLVM::VERSION` ([#13699](https://github.com/crystal-lang/crystal/pull/13699), thanks @HOMODELUNA) - _(macros)_ Do not add trailing `+` in `TypeNode#id` for virtual types ([#13708](https://github.com/crystal-lang/crystal/pull/13708), thanks @HertzDevil) - _(numeric)_ Fix `BigDecimal#round` for large digit counts in base 10 ([#13811](https://github.com/crystal-lang/crystal/pull/13811), thanks @HertzDevil) - _(serialization)_ Set encoding in `XML.parse_html` explicitly to UTF-8 ([#13705](https://github.com/crystal-lang/crystal/pull/13705), thanks @straight-shoota) - _(serialization)_ Fix error message when parsing unknown JSON enum value ([#13728](https://github.com/crystal-lang/crystal/pull/13728), thanks @willhbr) - _(serialization)_ Fix YAML scalar type validation error message ([#13771](https://github.com/crystal-lang/crystal/pull/13771), thanks @MistressRemilia) - _(serialization)_ Fix incorrect overflow in `UInt64.from_yaml` ([#13829](https://github.com/crystal-lang/crystal/pull/13829), thanks @HertzDevil) - _(system)_ Fix `Process.new` with nilable chdir parameter on Windows ([#13768](https://github.com/crystal-lang/crystal/pull/13768), thanks @straight-shoota) - _(system)_ Fix typo in unistd.cr ([#13850](https://github.com/crystal-lang/crystal/pull/13850), thanks @kojix2) - _(text)_ Fix `Char::Reader#each` bounds check after block ([#13817](https://github.com/crystal-lang/crystal/pull/13817), thanks @straight-shoota) - _(text)_ Minor fixup for `HTML.decode_codepoint` ([#13843](https://github.com/crystal-lang/crystal/pull/13843), thanks @straight-shoota) #### compiler - **[breaking]** Remove double `.cr.cr` extension in `require` path lookup ([#13749](https://github.com/crystal-lang/crystal/pull/13749), thanks @straight-shoota) - _(parser)_ Fix end location for `FunDef` ([#13789](https://github.com/crystal-lang/crystal/pull/13789), thanks @straight-shoota) - _(semantic)_ Fix lookup scope for `@[Primitive]` def's return type ([#13658](https://github.com/crystal-lang/crystal/pull/13658), thanks @HertzDevil) - _(semantic)_ Fix typo in call_error.cr ([#13764](https://github.com/crystal-lang/crystal/pull/13764), thanks @kojix2) #### tools - _(docs-generator)_ Fix octicon-link icon color on dark mode ([#13670](https://github.com/crystal-lang/crystal/pull/13670), thanks @GeopJr) - _(docs-generator)_ Allow word breaks between module names in docs ([#13827](https://github.com/crystal-lang/crystal/pull/13827), thanks @nobodywasishere) - _(docs-generator)_ Fix docs dark mode dropdown background on blink ([#13840](https://github.com/crystal-lang/crystal/pull/13840), thanks @GeopJr) - _(init)_ Fix shard crystal version in `crystal init` ([#13730](https://github.com/crystal-lang/crystal/pull/13730), thanks @xendk) - _(hierarchy)_: Fix byte sizes for `Proc`s inside extern structs ([#13711](https://github.com/crystal-lang/crystal/pull/13711), thanks @HertzDevil) ### Performance #### stdlib - Optimize `IO::Delimited` ([#11242](https://github.com/crystal-lang/crystal/pull/11242), thanks @asterite) - _(crypto)_ Use `IO::DEFAULT_BUFFER_SIZE` in `Digest#update` ([#13635](https://github.com/crystal-lang/crystal/pull/13635), thanks @carlhoerberg) - _(crypto)_ Fix memory leak in `OpenSSL::SSL::Socket#peer_certificate` ([#13785](https://github.com/crystal-lang/crystal/pull/13785), thanks @compumike) - _(files)_ Optimize `IO#read_string(0)` ([#13732](https://github.com/crystal-lang/crystal/pull/13732), thanks @jgaskins) - _(files)_ Avoid double file buffering ([#13780](https://github.com/crystal-lang/crystal/pull/13780), thanks @carlhoerberg) - _(llvm)_ Refactor `LLVM.default_target_triple` to avoid regex ([#13659](https://github.com/crystal-lang/crystal/pull/13659), thanks @straight-shoota) - _(numeric)_ Pre-allocate Dragonbox cache array ([#13649](https://github.com/crystal-lang/crystal/pull/13649), thanks @HertzDevil) - _(runtime)_ Avoid realloc callstack array when unwinding ([#13781](https://github.com/crystal-lang/crystal/pull/13781), thanks @carlhoerberg) - _(time)_ Optimize the constructors of `Time::Span` ([#13807](https://github.com/crystal-lang/crystal/pull/13807), thanks @erdian718) ### Refactor #### stdlib - Do not use nilable `Pointer`s ([#13710](https://github.com/crystal-lang/crystal/pull/13710), thanks @HertzDevil) - _(collection)_ Use `Set(T)` instead of `Hash(T, Bool)` ([#13611](https://github.com/crystal-lang/crystal/pull/13611), thanks @HertzDevil) - _(concurrency)_ Use `Fiber.inactive` inside `Fiber#run`'s `ensure` block ([#13701](https://github.com/crystal-lang/crystal/pull/13701), thanks @HertzDevil) - _(crypto)_ Use `JSON::Serializable` in `scripts/generate_ssl_server_defaults.cr` ([#13667](https://github.com/crystal-lang/crystal/pull/13667), thanks @HertzDevil) - _(crypto)_ Refactor narrow OpenSSL requires for digest implementations ([#13818](https://github.com/crystal-lang/crystal/pull/13818), thanks @straight-shoota) - _(networking)_ **[deprecation]** Add types to `HTTP::StaticFileHandler` ([#13778](https://github.com/crystal-lang/crystal/pull/13778), thanks @jkthorne) #### compiler - Restrict some boolean properties to `Bool` in the compiler ([#13614](https://github.com/crystal-lang/crystal/pull/13614), thanks @HertzDevil) ### Documentation #### stdlib - _(crypto)_ Fix docs for `Digest::SHA512` ([#13796](https://github.com/crystal-lang/crystal/pull/13796), thanks @jgaskins) - _(files)_ Document `Dir#mkdir`, `Dir#exists?` ([#13795](https://github.com/crystal-lang/crystal/pull/13795), thanks @jkthorne) - _(networking)_ Add documentation for `HTTP::Headers#add` ([#13762](https://github.com/crystal-lang/crystal/pull/13762), thanks @jkthorne) - _(text)_ Fix typo in regex.cr ([#13751](https://github.com/crystal-lang/crystal/pull/13751), thanks @beta-ziliani) ### Specs #### stdlib - _(numeric)_ Update specs for `Int::Primitive.from_json` ([#13835](https://github.com/crystal-lang/crystal/pull/13835), thanks @HertzDevil) - _(numeric)_ Remove overflowing `Float#to_u!` interpreter primitive specs ([#13737](https://github.com/crystal-lang/crystal/pull/13737), thanks @HertzDevil) - _(time)_ Clear `Time::Location` cache before `.load_android` specs ([#13718](https://github.com/crystal-lang/crystal/pull/13718), thanks @HertzDevil) ### Infrastructure - Update previous Crystal release - 1.9.2 ([#13650](https://github.com/crystal-lang/crystal/pull/13650), thanks @straight-shoota) - Update distribution-scripts ([#13776](https://github.com/crystal-lang/crystal/pull/13776), thanks @straight-shoota) - make: Add `generate_data` target for running generator scripts ([#13700](https://github.com/crystal-lang/crystal/pull/13700), thanks @straight-shoota) - Add shell completions for `clear_cache` ([#13636](https://github.com/crystal-lang/crystal/pull/13636), thanks @straight-shoota) - New changelog format ([#13662](https://github.com/crystal-lang/crystal/pull/13662), thanks @straight-shoota) - Detect developer mode in Windows installer ([#13681](https://github.com/crystal-lang/crystal/pull/13681), thanks @HertzDevil) - Update PGP key link ([#13754](https://github.com/crystal-lang/crystal/pull/13754), thanks @syeopite) - Fix log format in update-distribution-scripts.sh ([#13777](https://github.com/crystal-lang/crystal/pull/13777), thanks @straight-shoota) - _(ci)_ Trigger windows release jobs on tag ([#13683](https://github.com/crystal-lang/crystal/pull/13683), thanks @straight-shoota) - _(ci)_ Update GH Actions ([#13748](https://github.com/crystal-lang/crystal/pull/13748), thanks @renovate) - _(ci)_ Refactor `crystal_bootstrap_version` ([#13845](https://github.com/crystal-lang/crystal/pull/13845), thanks @straight-shoota) ================================================ FILE: doc/changelogs/v1.11.md ================================================ # Changelog 1.11 ## [1.11.2] (2024-01-18) [1.11.2]: https://github.com/crystal-lang/crystal/releases/1.11.2 ### Bugfixes #### stdlib - _(files)_ Fix missing `cause` parameter from `IO::Error#initialize` ([#14242](https://github.com/crystal-lang/crystal/pull/14242), thanks @straight-shoota) - _(runtime)_ Always use `%p` for pointers in `Crystal::System.print_error` ([#14186](https://github.com/crystal-lang/crystal/pull/14186), thanks @HertzDevil) - _(runtime)_ Fixup for always use `%p` for pointers in `Crystal::System.print_error` ([#14221](https://github.com/crystal-lang/crystal/pull/14221), thanks @HertzDevil) ### Infrastructure - Changelog for 1.11.2 ([#14249](https://github.com/crystal-lang/crystal/pull/14249), thanks @straight-shoota) ## [1.11.1] (2024-01-11) [1.11.1]: https://github.com/crystal-lang/crystal/releases/1.11.1 ### Bugfixes #### stdlib - _(crypto)_ Revert "Fix OpenSSL error handling for EOF (support for OpenSSL 3.2) (#14169)" ([#14217](https://github.com/crystal-lang/crystal/pull/14217), thanks @straight-shoota) #### compiler - _(interpreter)_ Remove pkg-config name for libgc as workaround for interpreter loader ([#14198](https://github.com/crystal-lang/crystal/pull/14198), thanks @straight-shoota) - _(semantic)_ Revert "Add `ReferenceStorage` for manual allocation of references (#14106)" ([#14207](https://github.com/crystal-lang/crystal/pull/14207), thanks @straight-shoota) ### Infrastructure - Changelog for 1.11.1 ([#14208](https://github.com/crystal-lang/crystal/pull/14208), thanks @straight-shoota) - Bump VERSION to 1.11.1-dev ([#14197](https://github.com/crystal-lang/crystal/pull/14197), thanks @straight-shoota) ## [1.11.0] (2024-01-08) [1.11.0]: https://github.com/crystal-lang/crystal/releases/1.11.0 ### Features #### lang - **[breaking]** Support `alignof` and `instance_alignof` ([#14087](https://github.com/crystal-lang/crystal/pull/14087), thanks @HertzDevil) - _(annotations)_ Support `dll` parameter in `@[Link]` ([#14131](https://github.com/crystal-lang/crystal/pull/14131), thanks @HertzDevil) - _(macros)_ Expose macro `Call` context via new `@caller` macro ivar ([#14048](https://github.com/crystal-lang/crystal/pull/14048), thanks @Blacksmoke16) #### stdlib - _(collection)_ Add `Enumerable#present?` ([#13866](https://github.com/crystal-lang/crystal/pull/13866), thanks @straight-shoota) - _(collection)_ Add `Enumerable#each_step` and `Iterable#each_step` ([#13610](https://github.com/crystal-lang/crystal/pull/13610), thanks @baseballlover723) - _(collection)_ Add `Enumerable(T)#to_set(& : T -> U) : Set(U) forall U` ([#12654](https://github.com/crystal-lang/crystal/pull/12654), thanks @caspiano) - _(collection)_ Add `Enumerable(T)#to_a(& : T -> U) forall U` ([#12653](https://github.com/crystal-lang/crystal/pull/12653), thanks @caspiano) - _(files)_ Add `IO::Error#target` ([#13865](https://github.com/crystal-lang/crystal/pull/13865), thanks @straight-shoota) - _(llvm)_ Add `LLVM::OperandBundleDef#dispose` ([#14095](https://github.com/crystal-lang/crystal/pull/14095), thanks @HertzDevil) - _(llvm)_ Windows: Use local configuration for LLVM when linking dynamically ([#14101](https://github.com/crystal-lang/crystal/pull/14101), thanks @HertzDevil) - _(macros)_ Add `CharLiteral#ord` ([#13910](https://github.com/crystal-lang/crystal/pull/13910), thanks @refi64) - _(macros)_ Add macro methods for `MacroIf` and `MacroFor` nodes ([#13902](https://github.com/crystal-lang/crystal/pull/13902), thanks @sbsoftware) - _(macros)_ Expose doc comments on `ASTNode` when generating docs ([#14050](https://github.com/crystal-lang/crystal/pull/14050), thanks @Blacksmoke16) - _(macros)_ Add macro methods for `ModuleDef` ([#14063](https://github.com/crystal-lang/crystal/pull/14063), thanks @HertzDevil) - _(macros)_ Add macro methods for `Include` and `Extend` ([#14064](https://github.com/crystal-lang/crystal/pull/14064), thanks @HertzDevil) - _(macros)_ Add macro methods for `ClassDef`, `EnumDef`, `AnnotationDef` ([#14072](https://github.com/crystal-lang/crystal/pull/14072), thanks @HertzDevil) - _(numeric)_ Implement `BigRational`'s rounding modes ([#13871](https://github.com/crystal-lang/crystal/pull/13871), thanks @HertzDevil) - _(numeric)_ Support full exponent range in `BigFloat#**(BigInt)` ([#13881](https://github.com/crystal-lang/crystal/pull/13881), thanks @HertzDevil) - _(numeric)_ Add `Math.fma` ([#13934](https://github.com/crystal-lang/crystal/pull/13934), thanks @HertzDevil) - _(numeric)_ Add `Number#integer?` ([#13936](https://github.com/crystal-lang/crystal/pull/13936), thanks @HertzDevil) - _(numeric)_ Publish `Int::Primitive#abs_unsigned` and `#neg_signed` ([#13938](https://github.com/crystal-lang/crystal/pull/13938), thanks @HertzDevil) - _(numeric)_ Add `Int::Primitive#to_signed`, `#to_signed!`, `#to_unsigned`, `#to_unsigned!` ([#13960](https://github.com/crystal-lang/crystal/pull/13960), thanks @HertzDevil) - _(numeric)_ Support `BigFloat#**` for all `Int::Primitive` arguments ([#13971](https://github.com/crystal-lang/crystal/pull/13971), thanks @HertzDevil) - _(numeric)_ Add `Float32::MIN_SUBNORMAL` and `Float64::MIN_SUBNORMAL` ([#13961](https://github.com/crystal-lang/crystal/pull/13961), thanks @HertzDevil) - _(numeric)_ Add `Float::Primitive.parse_hexfloat`, `.parse_hexfloat?`, `#to_hexfloat` ([#14027](https://github.com/crystal-lang/crystal/pull/14027), thanks @HertzDevil) - _(numeric)_ Implement `sprintf "%f"` in Crystal using Ryu Printf ([#14067](https://github.com/crystal-lang/crystal/pull/14067), thanks @HertzDevil) - _(numeric)_ Implement `sprintf "%e"` in Crystal ([#14084](https://github.com/crystal-lang/crystal/pull/14084), thanks @HertzDevil) - _(numeric)_ Implement `sprintf "%a"` in Crystal ([#14102](https://github.com/crystal-lang/crystal/pull/14102), thanks @HertzDevil) - _(numeric)_ Implement `sprintf "%g"` in Crystal ([#14123](https://github.com/crystal-lang/crystal/pull/14123), thanks @HertzDevil) - _(runtime)_ Add `Crystal::HOST_TRIPLE` and `TARGET_TRIPLE` ([#13823](https://github.com/crystal-lang/crystal/pull/13823), thanks @HertzDevil) - _(runtime)_ **[experimental]** Add `Reference.pre_initialize` and `.unsafe_construct` ([#14108](https://github.com/crystal-lang/crystal/pull/14108), thanks @HertzDevil) - _(runtime)_ **[experimental]** Add `ReferenceStorage` for manual allocation of references ([#14106](https://github.com/crystal-lang/crystal/pull/14106), thanks @HertzDevil) - _(serialization)_ Fix `StaticArray#to_json` ([#14104](https://github.com/crystal-lang/crystal/pull/14104), thanks @Vendicated) - _(specs)_ Add `crystal spec --dry-run` ([#13804](https://github.com/crystal-lang/crystal/pull/13804), thanks @nobodywasishere) - _(specs)_ Add `crystal spec --list-tags` ([#13616](https://github.com/crystal-lang/crystal/pull/13616), thanks @baseballlover723) - _(system)_ Respect Windows `Path` directory separators in `File.match?` ([#13912](https://github.com/crystal-lang/crystal/pull/13912), thanks @HertzDevil) - _(text)_ Support Unicode 15.1.0 ([#13812](https://github.com/crystal-lang/crystal/pull/13812), thanks @HertzDevil) - _(text)_ Add `UUID.v1`, `.v2`, `.v3`, `.v4`, `.v5` ([#13693](https://github.com/crystal-lang/crystal/pull/13693), thanks @threez) - _(text)_ Add `String` and `Char` patterns to `StringScanner` ([#13806](https://github.com/crystal-lang/crystal/pull/13806), thanks @funny-falcon) - _(text)_ Add `EOL`constant (End-Of-Line) ([#11303](https://github.com/crystal-lang/crystal/pull/11303), thanks @postmodern) - _(text)_ Add `Char::Reader#current_char?`, `#next_char?`, `#previous_char?` ([#14012](https://github.com/crystal-lang/crystal/pull/14012), thanks @HertzDevil) - _(text)_ Add `String#matches_full?` ([#13968](https://github.com/crystal-lang/crystal/pull/13968), thanks @straight-shoota) - _(text)_ Change `Regex::MatchData#to_s` to return matched substring ([#14115](https://github.com/crystal-lang/crystal/pull/14115), thanks @Vendicated) #### compiler - _(codegen)_ Add incremental optimization levels ([#13464](https://github.com/crystal-lang/crystal/pull/13464), thanks @kostya) - _(debugger)_ Support debug information for 64-bit or unsigned enums ([#14081](https://github.com/crystal-lang/crystal/pull/14081), thanks @HertzDevil) - _(interpreter)_ Support `instance_sizeof(T)` in the interpreter ([#14031](https://github.com/crystal-lang/crystal/pull/14031), thanks @HertzDevil) - _(interpreter)_ Support `-dynamic.lib` in Windows interpreter ([#14143](https://github.com/crystal-lang/crystal/pull/14143), thanks @HertzDevil) - _(interpreter)_ Support absolute paths in `CRYSTAL_INTERPRETER_LOADER_INFO` ([#14147](https://github.com/crystal-lang/crystal/pull/14147), thanks @HertzDevil) - _(interpreter)_ Add `Crystal::Repl#parse_and_interpret` ([#14138](https://github.com/crystal-lang/crystal/pull/14138), thanks @bcardiff) - _(semantic)_ Change short_reference for top-level methods to `::foo` ([#14071](https://github.com/crystal-lang/crystal/pull/14071), thanks @keshavbiswa) #### tools - _(docs-generator)_ Expose inherited macros in generated API docs ([#13810](https://github.com/crystal-lang/crystal/pull/13810), thanks @Blacksmoke16) - _(docs-generator)_ Order macros below class methods in generated docs ([#14024](https://github.com/crystal-lang/crystal/pull/14024), thanks @Blacksmoke16) - _(formatter)_ Do not remove trailing comma from multi-line macro/def parameters (not yet enabled) ([#14075](https://github.com/crystal-lang/crystal/pull/14075), thanks @Blacksmoke16) - _(unreachable)_ Add `--check` flag to `crystal tool unreachable` ([#13930](https://github.com/crystal-lang/crystal/pull/13930), thanks @straight-shoota) - _(unreachable)_ Add annotations to output of `crystal tool unreachable` ([#13927](https://github.com/crystal-lang/crystal/pull/13927), thanks @straight-shoota) - _(unreachable)_ Print relative paths in `crystal tool unreachable` ([#13929](https://github.com/crystal-lang/crystal/pull/13929), thanks @straight-shoota) - _(unreachable)_ Add CSV output format to `crystal tool unreachable` ([#13926](https://github.com/crystal-lang/crystal/pull/13926), thanks @straight-shoota) - _(unreachable)_ Add `--tallies` option to `crystal tool unreachable` ([#13969](https://github.com/crystal-lang/crystal/pull/13969), thanks @straight-shoota) ### Bugfixes #### stdlib - Fix `Box(T?)` crashing on `nil` ([#13893](https://github.com/crystal-lang/crystal/pull/13893), thanks @HertzDevil) - Fix typos in src ([#14053](https://github.com/crystal-lang/crystal/pull/14053), thanks @kojix2) - _(collection)_ Fix `Indexable#each_repeated_combination(n)` when `n > size` ([#14092](https://github.com/crystal-lang/crystal/pull/14092), thanks @HertzDevil) - _(concurrency)_ Make `Process#wait` asynchronous on Windows ([#13908](https://github.com/crystal-lang/crystal/pull/13908), thanks @HertzDevil) - _(concurrency)_ Fix math overflow after spawning `Int32::MAX + 1` fibers ([#14096](https://github.com/crystal-lang/crystal/pull/14096), thanks @ysbaddaden) - _(concurrency)_ Fix `can't resume a running fiber` ([#14128](https://github.com/crystal-lang/crystal/pull/14128), thanks @ysbaddaden) - _(crypto)_ Fix OpenSSL error handling for EOF (support for OpenSSL 3.2) ([#14169](https://github.com/crystal-lang/crystal/pull/14169), thanks @straight-shoota) - _(files)_ Fix `Globber.constant_entry?` matching patterns ([#13955](https://github.com/crystal-lang/crystal/pull/13955), thanks @GeopJr) - _(files)_ Fix `String::Buffer` and `IO::Memory` capacity to grow beyond 1GB ([#13989](https://github.com/crystal-lang/crystal/pull/13989), thanks @straight-shoota) - _(llvm)_ Fix a typo ([#13914](https://github.com/crystal-lang/crystal/pull/13914), thanks @kojix2) - _(numeric)_ Make `String#to_f(whitespace: false)` work with infinity and NaN ([#13875](https://github.com/crystal-lang/crystal/pull/13875), thanks @HertzDevil) - _(numeric)_ Use `LibGMP::SI` and `UI` for size checks, not `Long` and `ULong` ([#13874](https://github.com/crystal-lang/crystal/pull/13874), thanks @HertzDevil) - _(numeric)_ Fix integral part extraction in `Number#format` ([#14061](https://github.com/crystal-lang/crystal/pull/14061), thanks @HertzDevil) - _(numeric)_ Fix out-of-bounds access in `Int128::MIN.to_s(base: 2)` ([#14119](https://github.com/crystal-lang/crystal/pull/14119), thanks @HertzDevil) - _(numeric)_ Avoid double rounding in `Float#format` for nonnegative `decimal_place` ([#14129](https://github.com/crystal-lang/crystal/pull/14129), thanks @HertzDevil) - _(runtime)_ Avoid `@[ThreadLocal]` on Android ([#14025](https://github.com/crystal-lang/crystal/pull/14025), thanks @HertzDevil) - _(runtime)_ Never use string interpolation in `Crystal::System.print_error` ([#14114](https://github.com/crystal-lang/crystal/pull/14114), thanks @HertzDevil) - _(runtime)_ Fix segfault with next boehm gc (after v8.2.4) ([#14130](https://github.com/crystal-lang/crystal/pull/14130), thanks @ysbaddaden) - _(specs)_ Skip spec execution on error exit ([#13986](https://github.com/crystal-lang/crystal/pull/13986), thanks @straight-shoota) - _(system)_ Fix `FileUtils.ln_sf` to override special file types ([#13896](https://github.com/crystal-lang/crystal/pull/13896), thanks @straight-shoota) - _(system)_ Fix `Process.exists?` throwing errors on EPERM ([#13911](https://github.com/crystal-lang/crystal/pull/13911), thanks @refi64) - _(system)_ Fix portable shell command arguments in `Process#prepare_args` ([#13942](https://github.com/crystal-lang/crystal/pull/13942), thanks @GeopJr) - _(system)_ Windows: Do not close process handle in `Process#close` ([#13997](https://github.com/crystal-lang/crystal/pull/13997), thanks @HertzDevil) - _(system)_ Windows: clear `Crystal::System::Process#@completion_key` after use ([#14068](https://github.com/crystal-lang/crystal/pull/14068), thanks @HertzDevil) - _(system)_ Fix UTF-8 console input on Windows ([#13758](https://github.com/crystal-lang/crystal/pull/13758), thanks @erdian718) - _(text)_ Fix invalid UTF-8 handling in `Char::Reader#previous_char` ([#14013](https://github.com/crystal-lang/crystal/pull/14013), thanks @HertzDevil) - _(text)_ Fix `options` parameter for `String#split`, `#scan` ([#14183](https://github.com/crystal-lang/crystal/pull/14183), thanks @straight-shoota) - _(time)_ Fix time span overflow on `Int#milliseconds` and `Int#microseconds` ([#14105](https://github.com/crystal-lang/crystal/pull/14105), thanks @bcardiff) #### compiler - _(cli)_ Remove unnecessary file check for CLI arguments ([#13853](https://github.com/crystal-lang/crystal/pull/13853), thanks @straight-shoota) - _(cli)_ Check for invalid integers in compiler's CLI ([#13959](https://github.com/crystal-lang/crystal/pull/13959), thanks @HertzDevil) - _(cli)_ Fix compiler error message for invalid source file ([#14157](https://github.com/crystal-lang/crystal/pull/14157), thanks @straight-shoota) - _(codegen)_ Fix a typo in compiler source ([#14054](https://github.com/crystal-lang/crystal/pull/14054), thanks @kojix2) - _(codegen)_ Fix codegen error when discarding `is_a?` or `responds_to?`'s result ([#14148](https://github.com/crystal-lang/crystal/pull/14148), thanks @HertzDevil) - _(interpreter)_ Fix element alignment of `Tuple` and `NamedTuple` casts ([#14040](https://github.com/crystal-lang/crystal/pull/14040), thanks @HertzDevil) - _(interpreter)_ `Crystal::Loader`: Skip second linker member on Windows if absent ([#14111](https://github.com/crystal-lang/crystal/pull/14111), thanks @HertzDevil) - _(parser)_ Support `%r` and `%x` when not followed by delimiter start ([#13933](https://github.com/crystal-lang/crystal/pull/13933), thanks @HertzDevil) - _(parser)_ Fix location of global `Path` nodes in certain constructs ([#13932](https://github.com/crystal-lang/crystal/pull/13932), thanks @HertzDevil) - _(parser)_ Fix `ToSVisitor` for expanded string interpolation in backticks ([#13943](https://github.com/crystal-lang/crystal/pull/13943), thanks @straight-shoota) - _(parser)_ Fix location for "invalid trailing comma in call" errors ([#13964](https://github.com/crystal-lang/crystal/pull/13964), thanks @HertzDevil) - _(semantic)_ Fix check for file type ([#13760](https://github.com/crystal-lang/crystal/pull/13760), thanks @straight-shoota) - _(semantic)_ Fix private type definitions with namespaced `Path`s ([#13931](https://github.com/crystal-lang/crystal/pull/13931), thanks @HertzDevil) - _(semantic)_ Fix missing param count in compilation error message ([#13985](https://github.com/crystal-lang/crystal/pull/13985), thanks @koffeinfrei) - _(semantic)_ Fix `ReadInstanceVar` on typedefs ([#14044](https://github.com/crystal-lang/crystal/pull/14044), thanks @HertzDevil) - _(semantic)_ Fix global `Path` lookup inside macro when def has free variables ([#14073](https://github.com/crystal-lang/crystal/pull/14073), thanks @HertzDevil) - _(semantic)_ Add location information to implicit flag enum members ([#14127](https://github.com/crystal-lang/crystal/pull/14127), thanks @Blacksmoke16) #### tools - _(docs-generator)_ Fix `crystal docs` check `File.exists?` for `shard.yml` ([#13937](https://github.com/crystal-lang/crystal/pull/13937), thanks @straight-shoota) - _(docs-generator)_ Fix version sorting in API docs ([#13994](https://github.com/crystal-lang/crystal/pull/13994), thanks @m-o-e) - _(docs-generator)_ Strip whitespace in doc comment before determining summary line ([#14049](https://github.com/crystal-lang/crystal/pull/14049), thanks @Blacksmoke16) - _(docs-generator)_ Skip `Crystal::Macros` unless generating docs ([#13970](https://github.com/crystal-lang/crystal/pull/13970), thanks @straight-shoota) - _(init)_ Fix tool init error message when target exists but not a dir ([#13869](https://github.com/crystal-lang/crystal/pull/13869), thanks @straight-shoota) - _(unreachable)_ Fix infinite recursion of expanded nodes in `UnreachableVisitor` ([#13922](https://github.com/crystal-lang/crystal/pull/13922), thanks @straight-shoota) ### Chores #### lang - _(macros)_ **[deprecation]** Deprecate the splat operators in macro expressions ([#13939](https://github.com/crystal-lang/crystal/pull/13939), thanks @HertzDevil) #### stdlib - _(llvm)_ **[deprecation]** Deprecate `LLVM.start_multithreaded` and `.stop_multithreaded` ([#13949](https://github.com/crystal-lang/crystal/pull/13949), thanks @HertzDevil) ### Performance #### stdlib - _(concurrency)_ Skip indirections in `Crystal::Scheduler` ([#14098](https://github.com/crystal-lang/crystal/pull/14098), thanks @ysbaddaden) - _(numeric)_ Optimize `BigInt#&`, `#|`, `#^` with `Int::Primitive` arguments ([#14006](https://github.com/crystal-lang/crystal/pull/14006), thanks @HertzDevil) - _(numeric)_ Optimize `BigInt#bit` ([#13980](https://github.com/crystal-lang/crystal/pull/13980), thanks @HertzDevil) - _(numeric)_ Use `#trailing_zeros_count` in `Int#gcd` ([#14069](https://github.com/crystal-lang/crystal/pull/14069), thanks @HertzDevil) - _(serialization)_ Optimize `JSON::Builder#string` with byte-based algorithm ([#13915](https://github.com/crystal-lang/crystal/pull/13915), thanks @straight-shoota) - _(serialization)_ Improve performance of `JSON::Builder#string` with direct stringification ([#13950](https://github.com/crystal-lang/crystal/pull/13950), thanks @straight-shoota) - _(text)_ Refactor `HTML.unescape` in native Crystal ([#13844](https://github.com/crystal-lang/crystal/pull/13844), thanks @straight-shoota) - _(text)_ Refactor some uses of the blockless `String#split` ([#14001](https://github.com/crystal-lang/crystal/pull/14001), thanks @HertzDevil) ### Refactor #### stdlib - _(concurrency)_ Add `Crystal::System::Thread` ([#13814](https://github.com/crystal-lang/crystal/pull/13814), thanks @HertzDevil) - _(concurrency)_ Move `Thread#set_current_thread` to `Fiber` ([#14099](https://github.com/crystal-lang/crystal/pull/14099), thanks @ysbaddaden) - _(files)_ Use `IO.copy` in `IO#gets_to_end` ([#13990](https://github.com/crystal-lang/crystal/pull/13990), thanks @straight-shoota) - _(files)_ Do not use `pointerof(Path)` in the standard library ([#14144](https://github.com/crystal-lang/crystal/pull/14144), thanks @HertzDevil) - _(llvm)_ **[deprecation]** Remove `LLVMExtSetCurrentDebugLocation` from `llvm_ext.cc` for LLVM 9+ ([#13965](https://github.com/crystal-lang/crystal/pull/13965), thanks @HertzDevil) - _(llvm)_ Replace some deprecated LLVM bindings ([#13953](https://github.com/crystal-lang/crystal/pull/13953), thanks @HertzDevil) - _(llvm)_ Split `LibLLVM` by C headers ([#13948](https://github.com/crystal-lang/crystal/pull/13948), thanks @HertzDevil) - _(llvm)_ Support `LLVMSetTargetMachineGlobalISel` from LLVM 18 ([#14079](https://github.com/crystal-lang/crystal/pull/14079), thanks @HertzDevil) - _(llvm)_ Support the operand bundle API from LLVM 18 ([#14082](https://github.com/crystal-lang/crystal/pull/14082), thanks @HertzDevil) - _(numeric)_ Simplify `String::Formatter` when Ryu Printf is available ([#14132](https://github.com/crystal-lang/crystal/pull/14132), thanks @HertzDevil) - _(runtime)_ Implement most of `Crystal::System.print_error` in native Crystal ([#14116](https://github.com/crystal-lang/crystal/pull/14116), thanks @HertzDevil) - _(text)_ Drop `Char::Reader#@end` ([#13920](https://github.com/crystal-lang/crystal/pull/13920), thanks @straight-shoota) - _(text)_ Generate `src/html/entities.cr` automatically ([#13998](https://github.com/crystal-lang/crystal/pull/13998), thanks @HertzDevil) - _(time)_ Refactor leap year to use `divisible_by?` ([#13982](https://github.com/crystal-lang/crystal/pull/13982), thanks @meatball133) #### compiler - Remove relative path to vendored shards `markd` and `reply` ([#13992](https://github.com/crystal-lang/crystal/pull/13992), thanks @nobodywasishere) - _(cli)_ Generalize allowed values for compiler CLI `--format` option ([#13940](https://github.com/crystal-lang/crystal/pull/13940), thanks @straight-shoota) - _(parser)_ Use `Char#to_i?` in lexer ([#13841](https://github.com/crystal-lang/crystal/pull/13841), thanks @straight-shoota) #### tools - _(unreachable)_ Refactor `UnreachablePresenter` ([#13941](https://github.com/crystal-lang/crystal/pull/13941), thanks @straight-shoota) ### Documentation #### lang - _(macros)_ Add reference to book how merging macro expansion and call docs ([#14139](https://github.com/crystal-lang/crystal/pull/14139), thanks @Blacksmoke16) #### stdlib - _(collection)_ Fix documentation of `Hash#put_if_absent` ([#13898](https://github.com/crystal-lang/crystal/pull/13898), thanks @ilmanzo) - _(collection)_ Improve docs on initial/default values passed to `Array.new` and `Hash.new` ([#13962](https://github.com/crystal-lang/crystal/pull/13962), thanks @straight-shoota) - _(collection)_ Improve docs for `Iterator` step-by-step iteration ([#13967](https://github.com/crystal-lang/crystal/pull/13967), thanks @straight-shoota) - _(macros)_ Document `Crystal::Macros::MagicConstant` ([#14070](https://github.com/crystal-lang/crystal/pull/14070), thanks @HertzDevil) - _(serialization)_ Add docs and explicit type restriction for indent parameter of `JSON.build` ([#14140](https://github.com/crystal-lang/crystal/pull/14140), thanks @syeopite) - _(text)_ Add note about `Char::Reader`'s value semantics ([#14008](https://github.com/crystal-lang/crystal/pull/14008), thanks @HertzDevil) - _(text)_ Fix documentation for `String#index!` ([#14038](https://github.com/crystal-lang/crystal/pull/14038), thanks @gettalong) #### compiler - _(cli)_ Add optimization levels to manpage ([#14162](https://github.com/crystal-lang/crystal/pull/14162), thanks @straight-shoota) - _(cli)_ Add `unreachable` options to manpage ([#14164](https://github.com/crystal-lang/crystal/pull/14164), thanks @straight-shoota) - _(cli)_ Fix formatting in manpage ([#14163](https://github.com/crystal-lang/crystal/pull/14163), thanks @straight-shoota) ### Specs #### stdlib - Add `pending_wasm32` ([#14086](https://github.com/crystal-lang/crystal/pull/14086), thanks @HertzDevil) - _(concurrency)_ Workaround regular timeouts in `HTTP::Server` specs with MT ([#14097](https://github.com/crystal-lang/crystal/pull/14097), thanks @ysbaddaden) - _(files)_ Fix `File::AccessDeniedError` expectations in `File` specs ([#14029](https://github.com/crystal-lang/crystal/pull/14029), thanks @HertzDevil) - _(text)_ Refactor specs for `HTML.unescape` ([#13842](https://github.com/crystal-lang/crystal/pull/13842), thanks @straight-shoota) - _(text)_ Fix spec for `String#encode` and `String.new` on DragonFlyBSD ([#13944](https://github.com/crystal-lang/crystal/pull/13944), thanks @GeopJr) #### compiler - _(codegen)_ Remove `LLVMExtCreateMCJITCompilerForModule` from `llvm_ext.cc` ([#13966](https://github.com/crystal-lang/crystal/pull/13966), thanks @HertzDevil) - _(interpreter)_ Disable `mkfifo` spec for interpreter ([#14051](https://github.com/crystal-lang/crystal/pull/14051), thanks @HertzDevil) - _(interpreter)_ Fix interpreter specs on Windows ([#14145](https://github.com/crystal-lang/crystal/pull/14145), thanks @HertzDevil) #### tools - _(docs-generator)_ Use `top_level_semantic` in doc spec instead of `semantic` ([#9352](https://github.com/crystal-lang/crystal/pull/9352), thanks @makenowjust) ### Infrastructure - Changelog for 1.11.0 ([#14158](https://github.com/crystal-lang/crystal/pull/14158), thanks @straight-shoota) - Update previous Crystal release - 1.10.0 ([#13878](https://github.com/crystal-lang/crystal/pull/13878), thanks @straight-shoota) - Allow to specify git fork of distribution-scripts in CI ([#13976](https://github.com/crystal-lang/crystal/pull/13976), thanks @miry) - Extract `generate_data` to separate Makefile ([#14015](https://github.com/crystal-lang/crystal/pull/14015), thanks @straight-shoota) - Windows: Run specs in random order by default ([#14041](https://github.com/crystal-lang/crystal/pull/14041), thanks @HertzDevil) - Update shards 0.17.4 ([#14133](https://github.com/crystal-lang/crystal/pull/14133), thanks @straight-shoota) - Update distribution-scripts ([#14136](https://github.com/crystal-lang/crystal/pull/14136), thanks @straight-shoota) - Update GH Actions to v4 ([#14120](https://github.com/crystal-lang/crystal/pull/14120), thanks @renovate) - Embed logo image into repository and upgrade to SVG ([#14137](https://github.com/crystal-lang/crystal/pull/14137), thanks @straight-shoota) - Improvements for `github-changelog` script ([#14160](https://github.com/crystal-lang/crystal/pull/14160), thanks @straight-shoota) - Add `scripts/generate_llvm_version_info.cr` ([#14112](https://github.com/crystal-lang/crystal/pull/14112), thanks @HertzDevil) - Fix `make clean` to remove zipped manpages ([#14135](https://github.com/crystal-lang/crystal/pull/14135), thanks @straight-shoota) - Make `scripts/*.cr` all executable ([#13999](https://github.com/crystal-lang/crystal/pull/13999), thanks @HertzDevil) - Reformat changelog release headings ([#13663](https://github.com/crystal-lang/crystal/pull/13663), thanks @straight-shoota) - Merge `samples/.gitignore` into `.gitignore` ([#14134](https://github.com/crystal-lang/crystal/pull/14134), thanks @straight-shoota) - _(ci)_ Update GH Actions ([#13801](https://github.com/crystal-lang/crystal/pull/13801), thanks @renovate) - _(ci)_ Update LLVM patch version to LLVM 17.0.6 ([#14080](https://github.com/crystal-lang/crystal/pull/14080), thanks @straight-shoota) - _(ci)_ Configure Renovate Bot to add label `topic:infrastructure/ci` on PRs ([#14166](https://github.com/crystal-lang/crystal/pull/14166), thanks @straight-shoota) - _(ci)_ Update GH Actions ([#14165](https://github.com/crystal-lang/crystal/pull/14165), thanks @renovate) - _(ci)_ Distribute LLVM DLLs on Windows CI ([#14110](https://github.com/crystal-lang/crystal/pull/14110), thanks @HertzDevil) - _(ci)_ Use `CMAKE_MSVC_RUNTIME_LIBRARY` flag in win.yml ([#13900](https://github.com/crystal-lang/crystal/pull/13900), thanks @HertzDevil) ================================================ FILE: doc/changelogs/v1.12.md ================================================ # Changelog 1.12 ## [1.12.2] (2024-05-31) _Patch release with a bug fix necessary for support of latest libgc._ [1.12.2]: https://github.com/crystal-lang/crystal/releases/1.12.2 ### Bugfixes #### stdlib - _(runtime)_ Don't allocate in `Fiber.unsafe_each` and `Thread.unsafe_each` ([#14635], thanks @ysbaddaden) [#14635]: https://github.com/crystal-lang/crystal/pull/14635 ### Infrastructure - Changelog for 1.12.2 ([#14640], thanks @straight-shoota) [#14640]: https://github.com/crystal-lang/crystal/pull/14640 ## [1.12.1] (2024-04-11) [1.12.1]: https://github.com/crystal-lang/crystal/releases/1.12.1 ### Bugfixes #### tools - _(formatter)_ **[regression]** Fix formatter with whitespace before closing parenthesis ([#14471], thanks @straight-shoota) [#14471]: https://github.com/crystal-lang/crystal/pull/14471 ### Infrastructure - Changelog for 1.12.1 ([#14472], thanks @straight-shoota) [#14472]: https://github.com/crystal-lang/crystal/pull/14472 ## [1.12.0] (2024-04-09) [1.12.0]: https://github.com/crystal-lang/crystal/releases/1.12.0 ### Features #### lang - Allow multiple parameters and blocks for operators ending in `=` ([#14159], thanks @HertzDevil) [#14159]: https://github.com/crystal-lang/crystal/pull/14159 #### stdlib - _(concurrency)_ MT: reduce interleaved backtraces in spawn unhandled exceptions ([#14220], thanks @ysbaddaden) - _(concurrency)_ Fix: opening/reading from fifo/chardev files are blocking the thread ([#14255], thanks @ysbaddaden) - _(concurrency)_ Fix: Atomics and Locks (ARM, AArch64, X86) ([#14293], thanks @ysbaddaden) - _(files)_ Add `IO::FileDescriptor::Handle` ([#14390], thanks @straight-shoota) - _(macros)_ Add macro methods for lib-related nodes ([#14218], thanks @HertzDevil) - _(macros)_ Add macro methods for `Primitive` ([#14263], thanks @HertzDevil) - _(macros)_ Add macro methods for `TypeOf` ([#14262], thanks @HertzDevil) - _(macros)_ Add macro methods for `Alias` ([#14261], thanks @HertzDevil) - _(macros)_ Add macro methods for `Asm` and `AsmOperand` ([#14268], thanks @HertzDevil) - _(macros)_ Relax `delegate`'s setter detection ([#14282], thanks @HertzDevil) - _(numeric)_ Add `BigRational#%`, `#tdiv`, `#remainder` ([#14306], thanks @HertzDevil) - _(runtime)_ **[experimental]** Add `ReferenceStorage` for manual allocation of references ([#14270], thanks @HertzDevil) - _(runtime)_ Add MSVC invalid parameter handler ([#14313], thanks @HertzDevil) - _(system)_ Add `Signal#trap_handler?` ([#14126], thanks @stakach) - _(system)_ Thread: set name ([#14257], thanks @ysbaddaden) - _(system)_ Add `Process.on_terminate` ([#13694], thanks @stakach) - _(time)_ Add support for `Etc/UTC` time zone identifier without tzdb ([#14185], thanks @femto) [#14220]: https://github.com/crystal-lang/crystal/pull/14220 [#14255]: https://github.com/crystal-lang/crystal/pull/14255 [#14293]: https://github.com/crystal-lang/crystal/pull/14293 [#14390]: https://github.com/crystal-lang/crystal/pull/14390 [#14218]: https://github.com/crystal-lang/crystal/pull/14218 [#14263]: https://github.com/crystal-lang/crystal/pull/14263 [#14262]: https://github.com/crystal-lang/crystal/pull/14262 [#14261]: https://github.com/crystal-lang/crystal/pull/14261 [#14268]: https://github.com/crystal-lang/crystal/pull/14268 [#14282]: https://github.com/crystal-lang/crystal/pull/14282 [#14306]: https://github.com/crystal-lang/crystal/pull/14306 [#14270]: https://github.com/crystal-lang/crystal/pull/14270 [#14313]: https://github.com/crystal-lang/crystal/pull/14313 [#14126]: https://github.com/crystal-lang/crystal/pull/14126 [#14257]: https://github.com/crystal-lang/crystal/pull/14257 [#13694]: https://github.com/crystal-lang/crystal/pull/13694 [#14185]: https://github.com/crystal-lang/crystal/pull/14185 #### compiler - Add `CRYSTAL_CONFIG_CC` compiler config ([#14318], thanks @straight-shoota) - _(cli)_ Respect `NO_COLOR` in the compiler ([#14260], thanks @HertzDevil) - _(cli)_ Respect `--static` on Windows ([#14292], thanks @HertzDevil) - _(cli)_ Allow `--single-module` and `--threads` for `eval` and `spec` ([#14341], thanks @HertzDevil) - _(codegen)_ Add `--frame-pointers` to control preservation of frame pointers ([#13860], thanks @refi64) - _(codegen)_ x86-64 Solaris / illumos support ([#14343], thanks @HertzDevil) - _(interpreter)_ Support `@[Link]`'s DLL search order in the interpreter on Windows ([#14146], thanks @HertzDevil) - _(interpreter)_ Automatically detect MSVC tools on Windows interpreter ([#14391], thanks @HertzDevil) - _(parser)_ Allow calling `#[]=` with a block using method syntax ([#14161], thanks @HertzDevil) - _(semantic)_ Change short_reference for top-level macros to `::foo` ([#14203], thanks @femto) [#14318]: https://github.com/crystal-lang/crystal/pull/14318 [#14260]: https://github.com/crystal-lang/crystal/pull/14260 [#14292]: https://github.com/crystal-lang/crystal/pull/14292 [#14341]: https://github.com/crystal-lang/crystal/pull/14341 [#13860]: https://github.com/crystal-lang/crystal/pull/13860 [#14343]: https://github.com/crystal-lang/crystal/pull/14343 [#14146]: https://github.com/crystal-lang/crystal/pull/14146 [#14391]: https://github.com/crystal-lang/crystal/pull/14391 [#14161]: https://github.com/crystal-lang/crystal/pull/14161 [#14203]: https://github.com/crystal-lang/crystal/pull/14203 #### tools - Add `crystal tool flags` ([#14234], thanks @straight-shoota) - _(formatter)_ Add more whitespace around `ProcLiteral`s ([#14209], thanks @HertzDevil) [#14234]: https://github.com/crystal-lang/crystal/pull/14234 [#14209]: https://github.com/crystal-lang/crystal/pull/14209 ### Bugfixes #### lang - _(macros)_ Remove extra newline in top-level `FunDef`'s string representation ([#14212], thanks @HertzDevil) - _(macros)_ Remove `T*` and `T[N]` macro interpolation behavior inside libs ([#14215], thanks @HertzDevil) [#14212]: https://github.com/crystal-lang/crystal/pull/14212 [#14215]: https://github.com/crystal-lang/crystal/pull/14215 #### stdlib - _(collection)_ Fix `Hash#update` when default block also adds given key ([#14417], thanks @HertzDevil) - _(collection)_ Fix `Hash#put_if_absent` putting duplicate keys ([#14427], thanks @HertzDevil) - _(concurrency)_ Reserve stack space on non-main threads for crash recovery on Windows ([#14187], thanks @HertzDevil) - _(concurrency)_ Add memory barrier to `Mutex#unlock` on aarch64 ([#14272], thanks @jgaskins) - _(concurrency)_ init schedulers before we spawn fibers ([#14339], thanks @ysbaddaden) - _(files)_ Make `FileUtils.mv` work across filesystems on Windows ([#14320], thanks @HertzDevil) - _(llvm)_ Use correct string size for `LLVM::Type#inline_asm` ([#14265], thanks @HertzDevil) - _(llvm)_ Fix System V ABI for packed structs with misaligned fields ([#14324], thanks @HertzDevil) - _(networking)_ OpenSSL 3.x reports unexpected EOF as SSL error ([#14219], thanks @ysbaddaden) - _(numeric)_ Make equality between `Complex` and other numbers exact ([#14309], thanks @HertzDevil) - _(numeric)_ Fix `#hash` for the `Big*` number types ([#14308], thanks @HertzDevil) - _(runtime)_ Do not allocate memory in the segmentation fault signal handler ([#14327], thanks @HertzDevil) - _(runtime)_ Fix crash stack trace decoding on macOS ([#14335], thanks @HertzDevil) - _(runtime)_ `Crystal::RWLock` should be a struct ([#14345], thanks @ysbaddaden) - _(runtime)_ Fix `min_by?` in IOCP event loop `#run_once` ([#14394], thanks @straight-shoota) - _(serialization)_ `XML::Reader`: Disallow attributes containing null bytes ([#14193], thanks @HertzDevil) - _(serialization)_ Always call `LibXML.xmlInitParser` when requiring XML libraries ([#14191], thanks @HertzDevil) - _(system)_ Fix macro `Crystal::LIBRARY_PATH.split` when cross-compiling ([#14330], thanks @HertzDevil) - _(system)_ Add `SA_RESTART` flag to sigaction syscall ([#14351], thanks @ysbaddaden) - _(text)_ Add `Nil` return type restriction to `String::Formatter#consume_substitution` ([#14430], thanks @straight-shoota) [#14417]: https://github.com/crystal-lang/crystal/pull/14417 [#14427]: https://github.com/crystal-lang/crystal/pull/14427 [#14187]: https://github.com/crystal-lang/crystal/pull/14187 [#14272]: https://github.com/crystal-lang/crystal/pull/14272 [#14339]: https://github.com/crystal-lang/crystal/pull/14339 [#14320]: https://github.com/crystal-lang/crystal/pull/14320 [#14265]: https://github.com/crystal-lang/crystal/pull/14265 [#14324]: https://github.com/crystal-lang/crystal/pull/14324 [#14219]: https://github.com/crystal-lang/crystal/pull/14219 [#14309]: https://github.com/crystal-lang/crystal/pull/14309 [#14308]: https://github.com/crystal-lang/crystal/pull/14308 [#14327]: https://github.com/crystal-lang/crystal/pull/14327 [#14335]: https://github.com/crystal-lang/crystal/pull/14335 [#14345]: https://github.com/crystal-lang/crystal/pull/14345 [#14394]: https://github.com/crystal-lang/crystal/pull/14394 [#14193]: https://github.com/crystal-lang/crystal/pull/14193 [#14191]: https://github.com/crystal-lang/crystal/pull/14191 [#14330]: https://github.com/crystal-lang/crystal/pull/14330 [#14351]: https://github.com/crystal-lang/crystal/pull/14351 [#14430]: https://github.com/crystal-lang/crystal/pull/14430 #### compiler - _(cli)_ `build --no-codegen` output file name error ([#14239], thanks @apainintheneck) - _(codegen)_ Do not handle inline assembly with `"intel"` flag as AT&T syntax ([#14264], thanks @HertzDevil) - _(codegen)_ **[breaking]** Respect alignments above `alignof(Void*)` inside union values ([#14279], thanks @HertzDevil) - _(codegen)_ Fix stack corruption in union-to-union casts ([#14289], thanks @HertzDevil) - _(codegen)_ Don't copy DLL to output directory if file already exists ([#14315], thanks @HertzDevil) - _(codegen)_ Fix `Proc#call` that takes and returns large extern structs by value ([#14323], thanks @HertzDevil) - _(codegen)_ Never discard ivar initializer inside `.allocate` and `.pre_initialize` ([#14337], thanks @HertzDevil) - _(codegen)_ Use separate names for constant and class variable internals ([#14445], thanks @HertzDevil) - _(interpreter)_ fix fiber's resumable property ([#14252], thanks @ysbaddaden) - _(interpreter)_ Ensure all constants only have one initializer in the interpreter ([#14381], thanks @HertzDevil) - _(interpreter)_ Handle NaN comparisons in the interpreter ([#14441], thanks @HertzDevil) - _(interpreter)_ Check `UInt16#to_u8` for overflow in the interpreter ([#14436], thanks @HertzDevil) - _(interpreter)_ Fix interpreter internal overflow for `UInt128#to_f32` and `#to_f32!` ([#14437], thanks @HertzDevil) - _(parser)_ Fix name locations of `FunDef` and `External` nodes ([#14267], thanks @HertzDevil) - _(parser)_ Fix end locations of `Alias` nodes ([#14271], thanks @HertzDevil) [#14239]: https://github.com/crystal-lang/crystal/pull/14239 [#14264]: https://github.com/crystal-lang/crystal/pull/14264 [#14279]: https://github.com/crystal-lang/crystal/pull/14279 [#14289]: https://github.com/crystal-lang/crystal/pull/14289 [#14315]: https://github.com/crystal-lang/crystal/pull/14315 [#14323]: https://github.com/crystal-lang/crystal/pull/14323 [#14337]: https://github.com/crystal-lang/crystal/pull/14337 [#14445]: https://github.com/crystal-lang/crystal/pull/14445 [#14252]: https://github.com/crystal-lang/crystal/pull/14252 [#14381]: https://github.com/crystal-lang/crystal/pull/14381 [#14441]: https://github.com/crystal-lang/crystal/pull/14441 [#14436]: https://github.com/crystal-lang/crystal/pull/14436 [#14437]: https://github.com/crystal-lang/crystal/pull/14437 [#14267]: https://github.com/crystal-lang/crystal/pull/14267 [#14271]: https://github.com/crystal-lang/crystal/pull/14271 #### tools - _(formatter)_ Fix format for `asm` with comments ([#14278], thanks @straight-shoota) - _(formatter)_ Fix formatter for white space in `a.[b]` syntax ([#14346], thanks @straight-shoota) - _(formatter)_ Fix formatter on call without parentheses followed by doc comment ([#14354], thanks @straight-shoota) - _(formatter)_ Do not remove the whitespace in `foo ()` when formatting ([#14439], thanks @HertzDevil) [#14278]: https://github.com/crystal-lang/crystal/pull/14278 [#14346]: https://github.com/crystal-lang/crystal/pull/14346 [#14354]: https://github.com/crystal-lang/crystal/pull/14354 [#14439]: https://github.com/crystal-lang/crystal/pull/14439 ### Chores #### stdlib - _(concurrency)_ **[deprecation]** Drop flag `openbsd6.2` ([#14233], thanks @straight-shoota) - _(files)_ **[deprecation]** Deprecate timeout setters with `Number` arguments ([#14372], thanks @straight-shoota) [#14233]: https://github.com/crystal-lang/crystal/pull/14233 [#14372]: https://github.com/crystal-lang/crystal/pull/14372 #### compiler - _(codegen)_ Drop pinning Dwarf version 2 for android ([#14243], thanks @straight-shoota) [#14243]: https://github.com/crystal-lang/crystal/pull/14243 ### Performance #### stdlib - _(collection)_ Optimize hash lookup in `Enumerable#group_by` ([#14235], thanks @straight-shoota) - _(concurrency)_ Use per-scheduler stack pools (let's recycle) ([#14100], thanks @ysbaddaden) [#14235]: https://github.com/crystal-lang/crystal/pull/14235 [#14100]: https://github.com/crystal-lang/crystal/pull/14100 #### compiler - _(codegen)_ on demand distribution to forked processes ([#14273], thanks @ysbaddaden) - _(interpreter)_ Use `Fiber::StackPool` in the interpreter ([#14395], thanks @HertzDevil) [#14273]: https://github.com/crystal-lang/crystal/pull/14273 [#14395]: https://github.com/crystal-lang/crystal/pull/14395 ### Refactor #### stdlib - _(files)_ Replace some Microsoft C runtime funs with Win32 equivalents ([#14316], thanks @HertzDevil) - _(files)_ Move timeout properties to `Socket` and `IO::FileDescriptor` ([#14367], thanks @straight-shoota) - _(files)_ Add type restrictions to `#unbuffered_*` implementations ([#14382], thanks @straight-shoota) - _(networking)_ Refactor `HTTP::Client` timeout ivars to `Time::Span` ([#14371], thanks @straight-shoota) - _(networking)_ Refactor `Socket#system_receive` to return `Address` ([#14384], thanks @straight-shoota) - _(networking)_ Refactor `#system_connect` without yield ([#14383], thanks @straight-shoota) - _(numeric)_ Add `Crystal::Hasher.reduce_num` and `#number` ([#14304], thanks @HertzDevil) - _(runtime)_ Refactor and add comments to IOCP `#run_once` ([#14380], thanks @straight-shoota) - _(specs)_ **[deprecation]** Move most of spec runner's state into `Spec::CLI` ([#14170], thanks @HertzDevil) - _(specs)_ Add `Spec::Formatter#should_print_summary?` ([#14397], thanks @HertzDevil) [#14316]: https://github.com/crystal-lang/crystal/pull/14316 [#14367]: https://github.com/crystal-lang/crystal/pull/14367 [#14382]: https://github.com/crystal-lang/crystal/pull/14382 [#14371]: https://github.com/crystal-lang/crystal/pull/14371 [#14384]: https://github.com/crystal-lang/crystal/pull/14384 [#14383]: https://github.com/crystal-lang/crystal/pull/14383 [#14304]: https://github.com/crystal-lang/crystal/pull/14304 [#14380]: https://github.com/crystal-lang/crystal/pull/14380 [#14170]: https://github.com/crystal-lang/crystal/pull/14170 [#14397]: https://github.com/crystal-lang/crystal/pull/14397 #### compiler - Ensure `Crystal::Visitor#visit` returns `Bool` ([#14266], thanks @HertzDevil) - _(parser)_ Add `Token::Kind#unary_operator?` ([#14342], thanks @straight-shoota) - _(parser)_ Add `Lexer#wants_def_or_macro_name` ([#14352], thanks @straight-shoota) [#14266]: https://github.com/crystal-lang/crystal/pull/14266 [#14342]: https://github.com/crystal-lang/crystal/pull/14342 [#14352]: https://github.com/crystal-lang/crystal/pull/14352 ### Documentation #### stdlib - _(collection)_ Fix docs `:inherit:` pragma for `Indexable#first` ([#14296], thanks @lachlan) - _(collection)_ Fix `Hash.new(initial_capacity, &block)` doc to use relevant example ([#14429], thanks @lachlan) - _(crypto)_ Improve OpenSSL module documentation ([#14410], thanks @summer-alice) - _(numeric)_ Enhance docs for `Int#downto` ([#14176], thanks @jkthorne) - _(runtime)_ Document builtin constants ([#14276], thanks @straight-shoota) - _(runtime)_ Fix `Pointer#+(offset: Int64)` doc parameter name typo ([#14428], thanks @lachlan) - _(runtime)_ Improve documentation for `at_exit` handler conditions ([#14426], thanks @straight-shoota) - _(system)_ Fix typo in Signal docs ([#14400], thanks @joshrickard) - _(text)_ Fix `Colorize.enabled?`'s documentation ([#14258], thanks @HertzDevil) [#14296]: https://github.com/crystal-lang/crystal/pull/14296 [#14429]: https://github.com/crystal-lang/crystal/pull/14429 [#14410]: https://github.com/crystal-lang/crystal/pull/14410 [#14176]: https://github.com/crystal-lang/crystal/pull/14176 [#14276]: https://github.com/crystal-lang/crystal/pull/14276 [#14428]: https://github.com/crystal-lang/crystal/pull/14428 [#14426]: https://github.com/crystal-lang/crystal/pull/14426 [#14400]: https://github.com/crystal-lang/crystal/pull/14400 [#14258]: https://github.com/crystal-lang/crystal/pull/14258 ### Specs #### stdlib - Fix spelling in `spec/std/uri/params_spec.cr` ([#14302], thanks @jbampton) - _(files)_ Refactor expectations with `SpecChannelStatus` to be explicit ([#14378], thanks @straight-shoota) - _(files)_ Move some `IO::FileDescriptor` specs to the correct file ([#14431], thanks @HertzDevil) - _(system)_ Always preserve the environment for specs that modify `ENV` ([#14211], thanks @HertzDevil) - _(system)_ Ensure Windows time zone specs request `SeTimeZonePrivilege` properly ([#14297], thanks @HertzDevil) - _(text)_ Add single source of UTF-8 test sequences for specs ([#14433], thanks @HertzDevil) - _(time)_ Fix requires for `time/time_spec.cr` and `time/format_spec.cr` ([#14385], thanks @HertzDevil) [#14302]: https://github.com/crystal-lang/crystal/pull/14302 [#14378]: https://github.com/crystal-lang/crystal/pull/14378 [#14431]: https://github.com/crystal-lang/crystal/pull/14431 [#14211]: https://github.com/crystal-lang/crystal/pull/14211 [#14297]: https://github.com/crystal-lang/crystal/pull/14297 [#14433]: https://github.com/crystal-lang/crystal/pull/14433 [#14385]: https://github.com/crystal-lang/crystal/pull/14385 #### compiler - Remove the prelude from some compiler specs ([#14336], thanks @HertzDevil) - _(interpreter)_ Fix: don't run thread specs with the interpreter ([#14287], thanks @ysbaddaden) - _(interpreter)_ Add `pending_interpreted` ([#14386], thanks @HertzDevil) - _(interpreter)_ Remove `spec/interpreter_std_spec.cr` ([#14399], thanks @HertzDevil) - _(semantic)_ Enable `@[Primitive(:va_arg)]` semantic spec on Windows ([#14338], thanks @HertzDevil) [#14336]: https://github.com/crystal-lang/crystal/pull/14336 [#14287]: https://github.com/crystal-lang/crystal/pull/14287 [#14386]: https://github.com/crystal-lang/crystal/pull/14386 [#14399]: https://github.com/crystal-lang/crystal/pull/14399 [#14338]: https://github.com/crystal-lang/crystal/pull/14338 ### Infrastructure - Changelog for 1.12.0 ([#14232], thanks @straight-shoota) - Remove filtering of already mentioned PRs ([#14229], thanks @straight-shoota) - Mention RFC process in contribution instructions ([#14291], thanks @straight-shoota) - Drop Nikola sponsor mention from Readme ([#14290], thanks @straight-shoota) - Enhance changelog script to pull milestone info from GitHub ([#14230], thanks @straight-shoota) - Add `shard.yml` ([#14365], thanks @straight-shoota) - Update vendored dependencies ([#14373], thanks @straight-shoota) - Fix `Milestone` JSON bindings in `github-changelog` helper ([#14404], thanks @straight-shoota) - Make repository configurable for reusable `github-changelog` ([#14407], thanks @straight-shoota) - Use link refs for PR links in changelog ([#14406], thanks @straight-shoota) - Implement pagination for GitHub API in `github-changelog` helper ([#14412], thanks @straight-shoota) - Add `scripts/update-changelog.sh` ([#14231], thanks @straight-shoota) - Update distribution-scripts ([#14457], thanks @straight-shoota) - Change some line endings from CRLF to LF ([#14299], thanks @HertzDevil) - Update copyright year in NOTICE.md ([#14329], thanks @HertzDevil) - Install system dependencies in the Windows GUI installer ([#14328], thanks @HertzDevil) - Skip building `llvm_ext.cc` on LLVM 18 or above ([#14357], thanks @HertzDevil) - _(ci)_ Update previous Crystal release 1.11.0 ([#14189], thanks @straight-shoota) - _(ci)_ Update previous Crystal release 1.11.1 ([#14224], thanks @straight-shoota) - _(ci)_ Update previous Crystal release - 1.11.2 ([#14251], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#14246], thanks @renovate) - _(ci)_ Upgrade `resource_class` for `test_preview_mt` ([#14274], thanks @straight-shoota) - _(ci)_ Upgrade from old machine images approaching EOL ([#14275], thanks @straight-shoota) - _(ci)_ Update Windows library versions ([#14355], thanks @HertzDevil) - _(ci)_ Update cachix/install-nix-action action to v26 ([#14375], thanks @renovate) - _(ci)_ Update shards 0.18.0 ([#14411], thanks @straight-shoota) - _(ci)_ Support LLVM 18.1 ([#14277], thanks @HertzDevil) - _(ci)_ Use `Makefile.win` for Shards on Windows CI ([#14414], thanks @HertzDevil) [#14232]: https://github.com/crystal-lang/crystal/pull/14232 [#14229]: https://github.com/crystal-lang/crystal/pull/14229 [#14291]: https://github.com/crystal-lang/crystal/pull/14291 [#14290]: https://github.com/crystal-lang/crystal/pull/14290 [#14230]: https://github.com/crystal-lang/crystal/pull/14230 [#14365]: https://github.com/crystal-lang/crystal/pull/14365 [#14373]: https://github.com/crystal-lang/crystal/pull/14373 [#14404]: https://github.com/crystal-lang/crystal/pull/14404 [#14407]: https://github.com/crystal-lang/crystal/pull/14407 [#14406]: https://github.com/crystal-lang/crystal/pull/14406 [#14412]: https://github.com/crystal-lang/crystal/pull/14412 [#14231]: https://github.com/crystal-lang/crystal/pull/14231 [#14457]: https://github.com/crystal-lang/crystal/pull/14457 [#14299]: https://github.com/crystal-lang/crystal/pull/14299 [#14329]: https://github.com/crystal-lang/crystal/pull/14329 [#14328]: https://github.com/crystal-lang/crystal/pull/14328 [#14357]: https://github.com/crystal-lang/crystal/pull/14357 [#14189]: https://github.com/crystal-lang/crystal/pull/14189 [#14224]: https://github.com/crystal-lang/crystal/pull/14224 [#14251]: https://github.com/crystal-lang/crystal/pull/14251 [#14246]: https://github.com/crystal-lang/crystal/pull/14246 [#14274]: https://github.com/crystal-lang/crystal/pull/14274 [#14275]: https://github.com/crystal-lang/crystal/pull/14275 [#14355]: https://github.com/crystal-lang/crystal/pull/14355 [#14375]: https://github.com/crystal-lang/crystal/pull/14375 [#14411]: https://github.com/crystal-lang/crystal/pull/14411 [#14277]: https://github.com/crystal-lang/crystal/pull/14277 [#14414]: https://github.com/crystal-lang/crystal/pull/14414 ================================================ FILE: doc/changelogs/v1.13.md ================================================ # Changelog 1.13 ## [1.13.3] (2024-09-18) [1.13.3]: https://github.com/crystal-lang/crystal/releases/1.13.3 ### Bugfixes #### stdlib - **[regression]** Fix use global paths in macro bodies ([#14965], thanks @straight-shoota) - _(system)_ **[regression]** Fix `Process.exec` stream redirection on Windows ([#14986], thanks @HertzDevil) - _(text)_ **[regression]** Fix `String#index` and `#rindex` for `Char::REPLACEMENT` ([#14937], thanks @HertzDevil) [#14965]: https://github.com/crystal-lang/crystal/pull/14965 [#14986]: https://github.com/crystal-lang/crystal/pull/14986 [#14937]: https://github.com/crystal-lang/crystal/pull/14937 ### Infrastructure - Changelog for 1.13.3 ([#14991], thanks @straight-shoota) - _(ci)_ Enable runners from `runs-on.com` for Aarch64 CI ([#15007], thanks @straight-shoota) [#14991]: https://github.com/crystal-lang/crystal/pull/14991 [#15007]: https://github.com/crystal-lang/crystal/pull/15007 ## [1.13.2] (2024-08-20) [1.13.2]: https://github.com/crystal-lang/crystal/releases/1.13.2 ### Bugfixes #### stdlib - _(collection)_ Fix explicitly clear deleted `Hash::Entry` ([#14862], thanks @HertzDevil) [#14862]: https://github.com/crystal-lang/crystal/pull/14862 #### compiler - _(codegen)_ Fix `ReferenceStorage(T)` atomic if `T` has no inner pointers ([#14845], thanks @HertzDevil) - _(codegen)_ Fix misaligned store in `Bool` to union upcasts ([#14906], thanks @HertzDevil) - _(interpreter)_ Fix misaligned stack access in the interpreter ([#14843], thanks @HertzDevil) [#14845]: https://github.com/crystal-lang/crystal/pull/14845 [#14906]: https://github.com/crystal-lang/crystal/pull/14906 [#14843]: https://github.com/crystal-lang/crystal/pull/14843 ### Infrastructure - Changelog for 1.13.2 ([#14914], thanks @straight-shoota) [#14914]: https://github.com/crystal-lang/crystal/pull/14914 ## [1.13.1] (2024-07-12) [1.13.1]: https://github.com/crystal-lang/crystal/releases/1.13.1 ### Bugfixes #### stdlib - _(serialization)_ **[regression]** Revert "Optimize JSON parsing a bit" ([#14804], thanks @straight-shoota) [#14804]: https://github.com/crystal-lang/crystal/pull/14804 ### Infrastructure - Changelog for 1.13.1 ([#14806], thanks @straight-shoota) [#14806]: https://github.com/crystal-lang/crystal/pull/14806 ## [1.13.0] (2024-07-09) [1.13.0]: https://github.com/crystal-lang/crystal/releases/1.13.0 ### Features #### lang - Allow rescuing exceptions that include a module ([#14553], thanks @Blacksmoke16) - _(macros)_ Allow assignment to `_` inside macro expressions ([#14452], thanks @HertzDevil) [#14553]: https://github.com/crystal-lang/crystal/pull/14553 [#14452]: https://github.com/crystal-lang/crystal/pull/14452 #### stdlib - _(collection)_ Add `Array#insert_all` ([#14486], thanks @summer-alice) - _(collection)_ Improve compile time error for `#sort(&block : T, T -> U)` ([#14693], thanks @beta-ziliani) - _(concurrency)_ Add `WaitGroup` synchronization primitive ([#14167], thanks @ysbaddaden) - _(concurrency)_ Allow `Atomic`s of pointer types ([#14401], thanks @HertzDevil) - _(concurrency)_ Add `Thread.new` yields itself ([#14543], thanks @ysbaddaden) - _(concurrency)_ Add support for `Atomic(Bool)` ([#14532], thanks @ysbaddaden) - _(concurrency)_ Add `Thread.sleep(Time::Span)` ([#14715], thanks @ysbaddaden) - _(files)_ Implement `IO#tty?` in Win32 ([#14421], thanks @HertzDevil) - _(files)_ Implement `File.readable?` and `.writable?` in Win32 ([#14420], thanks @HertzDevil) - _(files)_ Make `File.readable?` and `.writable?` follow symlinks on Windows ([#14514], thanks @HertzDevil) - _(llvm)_ Add some missing `LLVM::Context` bindings ([#14612], thanks @ysbaddaden) - _(llvm)_ Do not strip the macOS target triple ([#14466], thanks @hovsater) - _(log)_ Support `UInt32` and `UInt64` in Log Context ([#14459], thanks @toddsundsted) - _(macros)_ Add AST node methods for macro-related nodes ([#14492], thanks @HertzDevil) - _(macros)_ Support short blocks in `#[]` operator call's macro interpolation ([#14523], thanks @HertzDevil) - _(macros)_ Add macro methods for `Select` ([#14600], thanks @HertzDevil) - _(macros)_ Add `TypeNode#private?`, `#public?` and `#visibility` ([#11696], thanks @Hadeweka) - _(macros)_ Add `StringLiteral#to_utf16` ([#14676], thanks @ysbaddaden) - _(networking)_ Relax type restriction of handlers in `HTTP::Server.new` to `Indexable(HTTP::Handler)` ([#14413], thanks @hugopl) - _(networking)_ **[security]** OpenSSL: don't change default cipher suites ([#14655], thanks @ysbaddaden) - _(networking)_ Allow parsing cookies with space in the value ([#14455], thanks @anton7c3) - _(runtime)_ Add `EventLoop::Socket` module ([#14643], thanks @straight-shoota) - _(runtime)_ Add `EventLoop::FileDescriptor` module ([#14639], thanks @straight-shoota) - _(runtime)_ Add `Crystal::Tracing` for runtime tracing ([#14659], thanks @ysbaddaden) - _(system)_ **[security]** **[breaking]** Disable implicit execution of batch files on Windows ([#14557], thanks @straight-shoota) - _(system)_ Add `EventLoop#run(blocking)` and `EventLoop#interrupt` ([#14568], thanks @ysbaddaden) - _(system)_ Add `Crystal::System::Time.ticks` ([#14620], thanks @ysbaddaden) - _(system)_ Add `Crystal::System::Thread.current_thread?`, `#scheduler?` ([#14660], thanks @ysbaddaden) - _(system)_ Protect fork/exec on targets that don't support atomic CLOEXEC ([#14674], thanks @ysbaddaden) - _(system)_ Add `Crystal::System.panic` ([#14733], thanks @ysbaddaden) - _(text)_ Add `Regex::MatchOptions` overload for `String#index!` ([#14462], thanks @HertzDevil) - _(text)_ Add `StringPool#get?` ([#14508], thanks @HertzDevil) - _(text)_ Add `pkg_config` names for `pcre2` and `pcre` ([#14584], thanks @straight-shoota) - _(text)_ Add UUID v7 ([#14732], thanks @jgaskins) - _(time)_ Add `Time::Error` ([#14743], thanks @Blacksmoke16) [#14486]: https://github.com/crystal-lang/crystal/pull/14486 [#14693]: https://github.com/crystal-lang/crystal/pull/14693 [#14167]: https://github.com/crystal-lang/crystal/pull/14167 [#14401]: https://github.com/crystal-lang/crystal/pull/14401 [#14543]: https://github.com/crystal-lang/crystal/pull/14543 [#14532]: https://github.com/crystal-lang/crystal/pull/14532 [#14715]: https://github.com/crystal-lang/crystal/pull/14715 [#14421]: https://github.com/crystal-lang/crystal/pull/14421 [#14420]: https://github.com/crystal-lang/crystal/pull/14420 [#14514]: https://github.com/crystal-lang/crystal/pull/14514 [#14612]: https://github.com/crystal-lang/crystal/pull/14612 [#14466]: https://github.com/crystal-lang/crystal/pull/14466 [#14459]: https://github.com/crystal-lang/crystal/pull/14459 [#14492]: https://github.com/crystal-lang/crystal/pull/14492 [#14523]: https://github.com/crystal-lang/crystal/pull/14523 [#14600]: https://github.com/crystal-lang/crystal/pull/14600 [#11696]: https://github.com/crystal-lang/crystal/pull/11696 [#14676]: https://github.com/crystal-lang/crystal/pull/14676 [#14413]: https://github.com/crystal-lang/crystal/pull/14413 [#14655]: https://github.com/crystal-lang/crystal/pull/14655 [#14455]: https://github.com/crystal-lang/crystal/pull/14455 [#14643]: https://github.com/crystal-lang/crystal/pull/14643 [#14639]: https://github.com/crystal-lang/crystal/pull/14639 [#14659]: https://github.com/crystal-lang/crystal/pull/14659 [#14557]: https://github.com/crystal-lang/crystal/pull/14557 [#14568]: https://github.com/crystal-lang/crystal/pull/14568 [#14620]: https://github.com/crystal-lang/crystal/pull/14620 [#14660]: https://github.com/crystal-lang/crystal/pull/14660 [#14674]: https://github.com/crystal-lang/crystal/pull/14674 [#14733]: https://github.com/crystal-lang/crystal/pull/14733 [#14462]: https://github.com/crystal-lang/crystal/pull/14462 [#14508]: https://github.com/crystal-lang/crystal/pull/14508 [#14584]: https://github.com/crystal-lang/crystal/pull/14584 [#14732]: https://github.com/crystal-lang/crystal/pull/14732 [#14743]: https://github.com/crystal-lang/crystal/pull/14743 #### compiler - _(codegen)_ Add compiler flags `-Os` and `-Oz` to optimize binary size ([#14463], thanks @ysbaddaden) - _(codegen)_ Add compiler support for AVR architecture (Arduino) ([#14393], thanks @ysbaddaden) [#14463]: https://github.com/crystal-lang/crystal/pull/14463 [#14393]: https://github.com/crystal-lang/crystal/pull/14393 #### tools - _(formatter)_ Allow new formatter styles for trailing comma and whitespace around proc literal ([#14726], thanks @Blacksmoke16) [#14726]: https://github.com/crystal-lang/crystal/pull/14726 ### Bugfixes #### lang - _(macros)_ Fix parsing of non-trailing `if` bodies inside macro expressions ([#14505], thanks @HertzDevil) - _(macros)_ Drop parentheses around `->` inside certain comma-separated lists ([#14506], thanks @HertzDevil) - _(macros)_ Fix indentation of `Select` nodes' macro interpolation ([#14510], thanks @HertzDevil) - _(macros)_ Fix indentation of parenthesized `Expressions#to_s` ([#14511], thanks @HertzDevil) [#14505]: https://github.com/crystal-lang/crystal/pull/14505 [#14506]: https://github.com/crystal-lang/crystal/pull/14506 [#14510]: https://github.com/crystal-lang/crystal/pull/14510 [#14511]: https://github.com/crystal-lang/crystal/pull/14511 #### stdlib - _(collection)_ **[regression]** Ensure `Enumerable#to_a` and `Enumerable#tally` properly retain return type of `T` ([#14447], thanks @Blacksmoke16) - _(collection)_ **[breaking]** Never raise `IndexError` in `#[]?(Range)` ([#14444], thanks @HertzDevil) - _(collection)_ **[breaking]** Fix `Set#to_a(&)` ([#14519], thanks @meatball133) - _(collection)_ Fix `Hash#rehash` to reset `@first` ([#14606], thanks @straight-shoota) - _(collection)_ Fix macro interpolation in `NamedTuple#from` ([#14790], thanks @HertzDevil) - _(collection)_ **[regression]** Fix regression with `NamedTuple.new` when using key with a hyphen ([#14785], thanks @Blacksmoke16) - _(files)_ Allow `#fsync` and `#flock_*` on `IO::FileDescriptor` ([#14432], thanks @HertzDevil) - _(files)_ Make `IO::FileDescriptor#tty?` return false for NUL on Windows ([#14509], thanks @HertzDevil) - _(files)_ Fix blockless `IO::FileDescriptor` echo and raw mode methods ([#14529], thanks @HertzDevil) - _(files)_ Remove target path's forward slashes in `File.symlink` on Windows ([#14522], thanks @HertzDevil) - _(files)_ Fix `IO#same_content?` accepting prefix on second stream ([#14664], thanks @straight-shoota) - _(files)_ Fix overflow in `File#read_at` for large offsets on Windows ([#14708], thanks @HertzDevil) - _(files)_ Fix `IO::FileDescriptor.new` for closed fd ([#14697], thanks @straight-shoota) - _(files)_ Fix `IO::Delimited` reading into limited slice with peek ([#14772], thanks @straight-shoota) - _(files)_ Fix `Compress::Gzip` extra field ([#14550], thanks @kojix2) - _(log)_ delete source from builder cache when finalize ([#14475], thanks @ysbaddaden) - _(networking)_ Fix `Socket#close` error handling on Windows ([#14517], thanks @HertzDevil) - _(networking)_ Set UTF-8 charset on directory listing in `HTTP::StaticFileHandler` ([#14546], thanks @alexkutsan) - _(networking)_ Don't pass socket file descriptors to subprocesses on Unix (`SOCK_CLOEXEC`) ([#14632], thanks @carlhoerberg) - _(networking)_ **[security]** OpenSSL: don't set default ECDH curve ([#14656], thanks @ysbaddaden) - _(networking)_ **[security]** OpenSSL: deprecate Mozilla's TLS Server recommendation ([#14657], thanks @ysbaddaden) - _(networking)_ use `SOCK_CLOEXEC` with `FD_CLOEXEC` fallback ([#14672], thanks @ysbaddaden) - _(networking)_ **[regression]** Fix regression on `Socket#connect` timeout type restriction ([#14755], thanks @straight-shoota) - _(networking)_ Drop default timeout for `Socket#connect` on Windows ([#14756], thanks @straight-shoota) - _(networking)_ don't hardcode alpn protocol byte size (OpenSSL) ([#14769], thanks @ysbaddaden) - _(numeric)_ Fix `BigRational#format` ([#14525], thanks @meatball133) - _(numeric)_ **[regression]** Restore leading zero in exponent for `printf("%e")` and `printf("%g")` ([#14695], thanks @straight-shoota) - _(runtime)_ Fix enable docs for builtin constants ([#14571], thanks @straight-shoota) - _(runtime)_ Fix `GC.malloc` for `gc_none` to clear memory ([#14746], thanks @straight-shoota) - _(serialization)_ Fix JSON discriminator for Bool `false` value ([#14779], thanks @dammer) - _(specs)_ Fix relative file paths in spec output ([#14725], thanks @straight-shoota) - _(system)_ Fix using `System.retry_with_buffer` with stack buffer ([#14615], thanks @straight-shoota) - _(system)_ Harmonize close on exec for `Socket` & `FileDescriptor` on Windows ([#14634], thanks @ysbaddaden) - _(system)_ Use `dup3` and `pipe2` to set `O_CLOEXEC` when available ([#14673], thanks @ysbaddaden) - _(system)_ Fix calls to `retry_with_buffer` when big buffer is necessary ([#14622], thanks @BlobCodes) - _(system)_ Fix `Process.run` with closed IO ([#14698], thanks @straight-shoota) - _(system)_ Prefer `strerror_r` over `strerror` for thread-safe errno ([#14764], thanks @ysbaddaden) - _(text)_ Make `String#sub` raise `IndexError` if index is equal to size ([#14458], thanks @HertzDevil) - _(text)_ Fix `libpcre2` version detection not working for `-RC{N}` versions ([#14478], thanks @Frityet) - _(text)_ Fix `Regex#inspect` with non-literal-compatible options ([#14575], thanks @straight-shoota) - _(text)_ Fix ECR escape sequences containing `-` ([#14739], thanks @HertzDevil) [#14447]: https://github.com/crystal-lang/crystal/pull/14447 [#14444]: https://github.com/crystal-lang/crystal/pull/14444 [#14519]: https://github.com/crystal-lang/crystal/pull/14519 [#14606]: https://github.com/crystal-lang/crystal/pull/14606 [#14790]: https://github.com/crystal-lang/crystal/pull/14790 [#14785]: https://github.com/crystal-lang/crystal/pull/14785 [#14432]: https://github.com/crystal-lang/crystal/pull/14432 [#14509]: https://github.com/crystal-lang/crystal/pull/14509 [#14529]: https://github.com/crystal-lang/crystal/pull/14529 [#14522]: https://github.com/crystal-lang/crystal/pull/14522 [#14664]: https://github.com/crystal-lang/crystal/pull/14664 [#14708]: https://github.com/crystal-lang/crystal/pull/14708 [#14697]: https://github.com/crystal-lang/crystal/pull/14697 [#14772]: https://github.com/crystal-lang/crystal/pull/14772 [#14550]: https://github.com/crystal-lang/crystal/pull/14550 [#14475]: https://github.com/crystal-lang/crystal/pull/14475 [#14517]: https://github.com/crystal-lang/crystal/pull/14517 [#14546]: https://github.com/crystal-lang/crystal/pull/14546 [#14632]: https://github.com/crystal-lang/crystal/pull/14632 [#14656]: https://github.com/crystal-lang/crystal/pull/14656 [#14657]: https://github.com/crystal-lang/crystal/pull/14657 [#14672]: https://github.com/crystal-lang/crystal/pull/14672 [#14755]: https://github.com/crystal-lang/crystal/pull/14755 [#14756]: https://github.com/crystal-lang/crystal/pull/14756 [#14769]: https://github.com/crystal-lang/crystal/pull/14769 [#14525]: https://github.com/crystal-lang/crystal/pull/14525 [#14695]: https://github.com/crystal-lang/crystal/pull/14695 [#14571]: https://github.com/crystal-lang/crystal/pull/14571 [#14746]: https://github.com/crystal-lang/crystal/pull/14746 [#14779]: https://github.com/crystal-lang/crystal/pull/14779 [#14725]: https://github.com/crystal-lang/crystal/pull/14725 [#14615]: https://github.com/crystal-lang/crystal/pull/14615 [#14634]: https://github.com/crystal-lang/crystal/pull/14634 [#14673]: https://github.com/crystal-lang/crystal/pull/14673 [#14622]: https://github.com/crystal-lang/crystal/pull/14622 [#14698]: https://github.com/crystal-lang/crystal/pull/14698 [#14764]: https://github.com/crystal-lang/crystal/pull/14764 [#14458]: https://github.com/crystal-lang/crystal/pull/14458 [#14478]: https://github.com/crystal-lang/crystal/pull/14478 [#14575]: https://github.com/crystal-lang/crystal/pull/14575 [#14739]: https://github.com/crystal-lang/crystal/pull/14739 #### compiler - _(codegen)_ Fix create new `target_machine` for every program ([#14694], thanks @straight-shoota) - _(codegen)_ Make `ReferenceStorage(T)` non-atomic if `T` is non-atomic ([#14730], thanks @HertzDevil) - _(codegen)_ Detect and error on failed codegen process ([#14762], thanks @ysbaddaden) - _(codegen)_ Fix stats and progress issues in codegen ([#14763], thanks @ysbaddaden) - _(debugger)_ Fix LLDB `crystal_formatters.py` for Python 3 ([#14665], thanks @zw963) - _(parser)_ Disallow assignments to calls with parentheses ([#14527], thanks @HertzDevil) - _(parser)_ Fix parser validate UTF-8 on first input byte ([#14750], thanks @straight-shoota) - _(semantic)_ Fix type def reopening type from parent namespace ([#11208], thanks @straight-shoota) - _(semantic)_ Fix `Crystal::Path#to_macro_id` for global path ([#14490], thanks @straight-shoota) - _(semantic)_ Fix `Class#===` on metaclass ([#11162], thanks @makenowjust) [#14694]: https://github.com/crystal-lang/crystal/pull/14694 [#14730]: https://github.com/crystal-lang/crystal/pull/14730 [#14762]: https://github.com/crystal-lang/crystal/pull/14762 [#14763]: https://github.com/crystal-lang/crystal/pull/14763 [#14665]: https://github.com/crystal-lang/crystal/pull/14665 [#14527]: https://github.com/crystal-lang/crystal/pull/14527 [#14750]: https://github.com/crystal-lang/crystal/pull/14750 [#11208]: https://github.com/crystal-lang/crystal/pull/11208 [#14490]: https://github.com/crystal-lang/crystal/pull/14490 [#11162]: https://github.com/crystal-lang/crystal/pull/11162 #### tools - _(docs-generator)_ Fix generate docs for builtins `HOST_TRIPLE` and `TARGET_TRIPLE` ([#14570], thanks @straight-shoota) - _(docs-generator)_ Decode URI component for search functionality in docs ([#14645], thanks @nobodywasishere) - _(formatter)_ Fix formatting for short block inside `#[]` operator call ([#14526], thanks @HertzDevil) - _(formatter)_ Fix formatter to skip trailing comma for single-line parameters ([#14713], thanks @Blacksmoke16) [#14570]: https://github.com/crystal-lang/crystal/pull/14570 [#14645]: https://github.com/crystal-lang/crystal/pull/14645 [#14526]: https://github.com/crystal-lang/crystal/pull/14526 [#14713]: https://github.com/crystal-lang/crystal/pull/14713 ### Chores #### stdlib - _(collection)_ Drop obsolete workaround in `Range#reverse_each` ([#14709], thanks @yxhuvud) - _(concurrency)_ Add `WaitGroup` to `docs_main.cr` ([#14624], thanks @straight-shoota) - _(files)_ **[deprecation]** Move `File.readable?`, `.writable?`, `.executable?` to `File::Info` ([#14484], thanks @straight-shoota) - _(networking)_ Drop `Crystal::System::Socket#system_send` ([#14637], thanks @straight-shoota) - _(networking)_ Add type restriction `host : String` in `TCPSocket` and `Addrinfo` ([#14703], thanks @straight-shoota) - _(runtime)_ Fix abstract def parameter name in `LibEvent::EventLoop#send_to` ([#14658], thanks @straight-shoota) - _(runtime)_ **[breaking]** Drop unused methods in `IO::Evented` ([#14666], thanks @straight-shoota) - _(runtime)_ Drop `IO::Overlapped` ([#14704], thanks @straight-shoota) [#14709]: https://github.com/crystal-lang/crystal/pull/14709 [#14624]: https://github.com/crystal-lang/crystal/pull/14624 [#14484]: https://github.com/crystal-lang/crystal/pull/14484 [#14637]: https://github.com/crystal-lang/crystal/pull/14637 [#14703]: https://github.com/crystal-lang/crystal/pull/14703 [#14658]: https://github.com/crystal-lang/crystal/pull/14658 [#14666]: https://github.com/crystal-lang/crystal/pull/14666 [#14704]: https://github.com/crystal-lang/crystal/pull/14704 #### compiler - _(codegen)_ **[breaking]** Remove `CRYSTAL_LIBRARY_RPATH` and delay-load helper ([#14598], thanks @HertzDevil) [#14598]: https://github.com/crystal-lang/crystal/pull/14598 ### Performance #### stdlib - _(collection)_ Optimize `Hash` for repeated removals and insertions ([#14539], thanks @HertzDevil) - _(runtime)_ Remove unnecessary explicit memory barriers on ARM ([#14567], thanks @ysbaddaden) - _(serialization)_ Optimize JSON parsing a bit ([#14366], thanks @asterite) - _(text)_ Use wrapping arithmetic for `Int::Primitive#unsafe_chr` ([#14443], thanks @HertzDevil) - _(text)_ Optimize `String#index(Char)` and `#rindex(Char)` for invalid UTF-8 ([#14461], thanks @HertzDevil) - _(text)_ Optimize `String#to_utf16` ([#14671], thanks @straight-shoota) [#14539]: https://github.com/crystal-lang/crystal/pull/14539 [#14567]: https://github.com/crystal-lang/crystal/pull/14567 [#14366]: https://github.com/crystal-lang/crystal/pull/14366 [#14443]: https://github.com/crystal-lang/crystal/pull/14443 [#14461]: https://github.com/crystal-lang/crystal/pull/14461 [#14671]: https://github.com/crystal-lang/crystal/pull/14671 ### Refactor #### stdlib - Remove unnecessary calls to `#unsafe_as(UInt64)` etc. ([#14686], thanks @straight-shoota) - _(crypto)_ Replace calls to `StaticArray(UInt8, 1)#unsafe_as(UInt8)` ([#14685], thanks @straight-shoota) - _(files)_ Remove calls to `LibC._setmode` ([#14419], thanks @HertzDevil) - _(files)_ Use file handles directly instead of C file descriptors on Win32 ([#14501], thanks @HertzDevil) - _(files)_ Refactor win32 `System::FileDescriptor#unbuffered_{read,write}` ([#14607], thanks @straight-shoota) - _(files)_ Extract `#system_read` and `#system_write` for `FileDescriptor` and `Socket` ([#14626], thanks @straight-shoota) - _(files)_ Drop unused slice parameters of `#evented_*` methods ([#14627], thanks @straight-shoota) - _(networking)_ Refactor use `IO#read_byte` instead of `#read_char` in `HTTP::ChunkedContent` ([#14548], thanks @straight-shoota) - _(runtime)_ `Thread` owns its current fiber (instead of `Crystal::Scheduler`) ([#14554], thanks @ysbaddaden) - _(runtime)_ Use `Fiber#enqueue` ([#14561], thanks @ysbaddaden) - _(runtime)_ Add `Crystal::EventLoop.current` ([#14559], thanks @ysbaddaden) - _(runtime)_ Add `Fiber.suspend` ([#14560], thanks @ysbaddaden) - _(runtime)_ Remove `OverlappedOperation#synchronous` ([#14663], thanks @straight-shoota) - _(runtime)_ Rename `Crystal::Iocp` to `Crystal::IOCP` ([#14662], thanks @straight-shoota) - _(runtime)_ Unify `EventLoop.create` ([#14661], thanks @straight-shoota) - _(serialization)_ Replace `type` declarations for void pointers with `alias` in `libxml2` ([#14494], thanks @straight-shoota) - _(serialization)_ Refactor `JSON::Any#size` to use two branches instead of three ([#14533], thanks @meatball133) - _(specs)_ Move `Spec` context state into `Spec::CLI` ([#14259], thanks @HertzDevil) - _(system)_ Update `WinError#to_errno` ([#14515], thanks @HertzDevil) - _(system)_ Rename `Crystal::System.print_error(fmt, *args, &)` to `printf` ([#14617], thanks @ysbaddaden) - _(system)_ Refactor `Crystal::System.retry_with_buffer` calling `#to_slice` ([#14614], thanks @straight-shoota) - _(system)_ Extract system implementation of `UNIXSocket.pair` as `Crystal::System::Socket.socketpair` ([#14675], thanks @ysbaddaden) - _(system)_ Remove calls to `Pointer.new(Int)` ([#14683], thanks @straight-shoota) - _(system)_ Cleanup for `IOCP::OverlappedOperation` ([#14723], thanks @straight-shoota) - _(system)_ Refactor `IOCP::OverlappedOperation` internalize `handle` and `wait_for_completion` ([#14724], thanks @straight-shoota) [#14686]: https://github.com/crystal-lang/crystal/pull/14686 [#14685]: https://github.com/crystal-lang/crystal/pull/14685 [#14419]: https://github.com/crystal-lang/crystal/pull/14419 [#14501]: https://github.com/crystal-lang/crystal/pull/14501 [#14607]: https://github.com/crystal-lang/crystal/pull/14607 [#14626]: https://github.com/crystal-lang/crystal/pull/14626 [#14627]: https://github.com/crystal-lang/crystal/pull/14627 [#14548]: https://github.com/crystal-lang/crystal/pull/14548 [#14554]: https://github.com/crystal-lang/crystal/pull/14554 [#14561]: https://github.com/crystal-lang/crystal/pull/14561 [#14559]: https://github.com/crystal-lang/crystal/pull/14559 [#14560]: https://github.com/crystal-lang/crystal/pull/14560 [#14663]: https://github.com/crystal-lang/crystal/pull/14663 [#14662]: https://github.com/crystal-lang/crystal/pull/14662 [#14661]: https://github.com/crystal-lang/crystal/pull/14661 [#14494]: https://github.com/crystal-lang/crystal/pull/14494 [#14533]: https://github.com/crystal-lang/crystal/pull/14533 [#14259]: https://github.com/crystal-lang/crystal/pull/14259 [#14515]: https://github.com/crystal-lang/crystal/pull/14515 [#14617]: https://github.com/crystal-lang/crystal/pull/14617 [#14614]: https://github.com/crystal-lang/crystal/pull/14614 [#14675]: https://github.com/crystal-lang/crystal/pull/14675 [#14683]: https://github.com/crystal-lang/crystal/pull/14683 [#14723]: https://github.com/crystal-lang/crystal/pull/14723 [#14724]: https://github.com/crystal-lang/crystal/pull/14724 #### compiler - _(codegen)_ Add `Program#size_t` and `Target#size_bit_width` ([#14442], thanks @ysbaddaden) - _(parser)_ Replace `Crystal::Select::When` with `Crystal::When` ([#14497], thanks @HertzDevil) [#14442]: https://github.com/crystal-lang/crystal/pull/14442 [#14497]: https://github.com/crystal-lang/crystal/pull/14497 ### Documentation #### stdlib - _(collection)_ Fix doc for `Set#proper_superset_of?` ([#14516], thanks @meatball133) - _(collection)_ Fix result formatting in code example for `Indexable#[]?` ([#14721], thanks @meatball133) - _(concurrency)_ Fix example for `WeakRef` by removing `ref.value` call ([#10846], thanks @hugopl) - _(networking)_ Improve API docs for `Socket#send` ([#14638], thanks @straight-shoota) - _(networking)_ Add documentation for `HTTP::WebSocket#stream` ([#14537], thanks @meatball133) - _(numeric)_ Add documentation for complex methods inside Number ([#14538], thanks @meatball133) - _(runtime)_ Add documentation for standard streams blocking behaviour ([#14577], thanks @straight-shoota) - _(serialization)_ Fix docs for `CSV::Builder#row(&)` ([#14736], thanks @philipp-classen) - _(system)_ **[breaking]** Undocument `IO::Evented` ([#14749], thanks @straight-shoota) - _(system)_ Fix code example for `Process.on_terminate` ([#14798], thanks @philipp-classen) - _(text)_ Fix docs for `Char#ascii_number?` stating wrong minimum base ([#14521], thanks @meatball133) - _(text)_ Enhance documentation for regex options `NO_UTF_CHECK` ([#14542], thanks @straight-shoota) [#14516]: https://github.com/crystal-lang/crystal/pull/14516 [#14721]: https://github.com/crystal-lang/crystal/pull/14721 [#10846]: https://github.com/crystal-lang/crystal/pull/10846 [#14638]: https://github.com/crystal-lang/crystal/pull/14638 [#14537]: https://github.com/crystal-lang/crystal/pull/14537 [#14538]: https://github.com/crystal-lang/crystal/pull/14538 [#14577]: https://github.com/crystal-lang/crystal/pull/14577 [#14736]: https://github.com/crystal-lang/crystal/pull/14736 [#14749]: https://github.com/crystal-lang/crystal/pull/14749 [#14798]: https://github.com/crystal-lang/crystal/pull/14798 [#14521]: https://github.com/crystal-lang/crystal/pull/14521 [#14542]: https://github.com/crystal-lang/crystal/pull/14542 ### Specs #### stdlib - Remove incorrect uses of `describe` ([#14757], thanks @HertzDevil) - _(files)_ Add spec for `Compress::Gzip::Writer` with `extra` ([#14788], thanks @straight-shoota) - _(runtime)_ Add specs for `Pointer::Appender` ([#14719], thanks @straight-shoota) - _(text)_ Add test helper for `normalize/regex_spec` ([#14545], thanks @straight-shoota) [#14757]: https://github.com/crystal-lang/crystal/pull/14757 [#14788]: https://github.com/crystal-lang/crystal/pull/14788 [#14719]: https://github.com/crystal-lang/crystal/pull/14719 [#14545]: https://github.com/crystal-lang/crystal/pull/14545 ### Infrastructure - Changelog for 1.13.0 ([#14712], thanks @straight-shoota) - Update previous Crystal release 1.12.1 ([#14480], thanks @straight-shoota) - Highlight regression bugfixes in changelog ([#14474], thanks @straight-shoota) - Write release version to `src/VERSION` in `update-changelog` and `release-update` ([#14547], thanks @straight-shoota) - Fix `shell.nix` use `llvmPackages.bintools` with wrapper for rpath config ([#14583], thanks @straight-shoota) - Add `src/SOURCE_DATE_EPOCH` to release tree ([#14574], thanks @straight-shoota) - Update distribution-scripts ([#14562], thanks @straight-shoota) - Update distribution-scripts ([#14594], thanks @straight-shoota) - Use `boehmgc` package from nixpkgs in `shell.nix` ([#14591], thanks @straight-shoota) - Simplify LLVM dependency in `shell.nix` ([#14590], thanks @straight-shoota) - Fix nixpkgs `pkg-config` name in `shell.nix` ([#14593], thanks @straight-shoota) - Update previous Crystal release 1.12.2 ([#14647], thanks @straight-shoota) - Update distribution-scripts ([#14648], thanks @straight-shoota) - Update distribution-scripts ([#14714], thanks @straight-shoota) - Update distribution-scripts ([#14776], thanks @straight-shoota) - Fix changelog generator increase topic priority for `infrastructure` ([#14781], thanks @straight-shoota) - Remove `SetShouldExit` in Powershell wrapper ([#13769], thanks @straight-shoota) - _(ci)_ Run `primitives_spec` with the interpreter on CI ([#14438], thanks @HertzDevil) - _(ci)_ Add LLVM 18 to LLVM CI ([#14565], thanks @HertzDevil) - _(ci)_ Update to Ruby 3 in macOS circleCI runner ([#14777], thanks @straight-shoota) - _(ci)_ Distribute `shards.pdb` on Windows ([#14415], thanks @HertzDevil) - _(ci)_ Drop Windows CI workaround for 1.12.0-dev ([#14483], thanks @HertzDevil) [#14712]: https://github.com/crystal-lang/crystal/pull/14712 [#14480]: https://github.com/crystal-lang/crystal/pull/14480 [#14474]: https://github.com/crystal-lang/crystal/pull/14474 [#14547]: https://github.com/crystal-lang/crystal/pull/14547 [#14583]: https://github.com/crystal-lang/crystal/pull/14583 [#14574]: https://github.com/crystal-lang/crystal/pull/14574 [#14562]: https://github.com/crystal-lang/crystal/pull/14562 [#14594]: https://github.com/crystal-lang/crystal/pull/14594 [#14591]: https://github.com/crystal-lang/crystal/pull/14591 [#14590]: https://github.com/crystal-lang/crystal/pull/14590 [#14593]: https://github.com/crystal-lang/crystal/pull/14593 [#14647]: https://github.com/crystal-lang/crystal/pull/14647 [#14648]: https://github.com/crystal-lang/crystal/pull/14648 [#14714]: https://github.com/crystal-lang/crystal/pull/14714 [#14776]: https://github.com/crystal-lang/crystal/pull/14776 [#14781]: https://github.com/crystal-lang/crystal/pull/14781 [#13769]: https://github.com/crystal-lang/crystal/pull/13769 [#14438]: https://github.com/crystal-lang/crystal/pull/14438 [#14565]: https://github.com/crystal-lang/crystal/pull/14565 [#14777]: https://github.com/crystal-lang/crystal/pull/14777 [#14415]: https://github.com/crystal-lang/crystal/pull/14415 [#14483]: https://github.com/crystal-lang/crystal/pull/14483 ================================================ FILE: doc/changelogs/v1.14.md ================================================ # Changelog 1.14 ## [1.14.1] (2025-01-08) [1.14.1]: https://github.com/crystal-lang/crystal/releases/1.14.1 ### Bugfixes #### tools - _(formatter)_ Handle trailing comma with multiple parameters on the same line ([#15097], thanks @Blacksmoke16) [#15097]: https://github.com/crystal-lang/crystal/pull/15097 ### Infrastructure - Changelog for 1.14.1 ([#15323], thanks @straight-shoota) - _(ci)_ Update XCode 15.3.0 in circleci ([#15327], thanks @straight-shoota) [#15323]: https://github.com/crystal-lang/crystal/pull/15323 [#15327]: https://github.com/crystal-lang/crystal/pull/15327 ## [1.14.0] (2024-10-09) [1.14.0]: https://github.com/crystal-lang/crystal/releases/1.14.0 ### Features #### lang - Allow `^` in constant numeric expressions ([#14951], thanks @HertzDevil) [#14951]: https://github.com/crystal-lang/crystal/pull/14951 #### stdlib - Add support for Windows on aarch64 ([#14911], thanks @HertzDevil) - _(collection)_ **[breaking]** Add support for negative start index in `Slice#[start, count]` ([#14778], thanks @ysbaddaden) - _(collection)_ Add `Slice#same?` ([#14728], thanks @straight-shoota) - _(concurrency)_ Add `WaitGroup.wait` and `WaitGroup#spawn` ([#14837], thanks @jgaskins) - _(concurrency)_ Open non-blocking regular files as overlapped on Windows ([#14921], thanks @HertzDevil) - _(concurrency)_ Support non-blocking `File#read` and `#write` on Windows ([#14940], thanks @HertzDevil) - _(concurrency)_ Support non-blocking `File#read_at` on Windows ([#14958], thanks @HertzDevil) - _(concurrency)_ Support non-blocking `Process.run` standard streams on Windows ([#14941], thanks @HertzDevil) - _(concurrency)_ Support `IO::FileDescriptor#flock_*` on non-blocking files on Windows ([#14943], thanks @HertzDevil) - _(concurrency)_ Emulate non-blocking `STDIN` console on Windows ([#14947], thanks @HertzDevil) - _(concurrency)_ Async DNS resolution on Windows ([#14979], thanks @HertzDevil) - _(crypto)_ Update `LibCrypto` bindings for LibreSSL 3.5+ ([#14872], thanks @straight-shoota) - _(llvm)_ Expose LLVM instruction builder for `neg` and `fneg` ([#14774], thanks @JarnaChao09) - _(llvm)_ **[experimental]** Add minimal LLVM OrcV2 bindings ([#14887], thanks @HertzDevil) - _(llvm)_ Add `LLVM::Builder#finalize` ([#14892], thanks @JarnaChao09) - _(llvm)_ Support LLVM 19.1 ([#14842], thanks @HertzDevil) - _(macros)_ Add `Crystal::Macros::TypeNode#has_inner_pointers?` ([#14847], thanks @HertzDevil) - _(macros)_ Add `HashLiteral#has_key?` and `NamedTupleLiteral#has_key?` ([#14890], thanks @kamil-gwozdz) - _(numeric)_ Implement floating-point manipulation functions for `BigFloat` ([#11007], thanks @HertzDevil) - _(runtime)_ Stop & start the world (undocumented API) ([#14729], thanks @ysbaddaden) - _(runtime)_ Add `Pointer::Appender#to_slice` ([#14874], thanks @straight-shoota) - _(serialization)_ Add `URI.from_json_object_key?` and `URI#to_json_object_key` ([#14834], thanks @nobodywasishere) - _(serialization)_ Add `URI::Params::Serializable` ([#14684], thanks @Blacksmoke16) - _(system)_ Enable full backtrace for exception in process spawn ([#14796], thanks @straight-shoota) - _(system)_ Implement `System::User` on Windows ([#14933], thanks @HertzDevil) - _(system)_ Implement `System::Group` on Windows ([#14945], thanks @HertzDevil) - _(system)_ Add methods to `Crystal::EventLoop` ([#14977], thanks @ysbaddaden) - _(text)_ Add `underscore_to_space` option to `String#titleize` ([#14822], thanks @Blacksmoke16) - _(text)_ Support Unicode 16.0.0 ([#14997], thanks @HertzDevil) [#14911]: https://github.com/crystal-lang/crystal/pull/14911 [#14778]: https://github.com/crystal-lang/crystal/pull/14778 [#14728]: https://github.com/crystal-lang/crystal/pull/14728 [#14837]: https://github.com/crystal-lang/crystal/pull/14837 [#14921]: https://github.com/crystal-lang/crystal/pull/14921 [#14940]: https://github.com/crystal-lang/crystal/pull/14940 [#14958]: https://github.com/crystal-lang/crystal/pull/14958 [#14941]: https://github.com/crystal-lang/crystal/pull/14941 [#14943]: https://github.com/crystal-lang/crystal/pull/14943 [#14947]: https://github.com/crystal-lang/crystal/pull/14947 [#14979]: https://github.com/crystal-lang/crystal/pull/14979 [#14872]: https://github.com/crystal-lang/crystal/pull/14872 [#14774]: https://github.com/crystal-lang/crystal/pull/14774 [#14887]: https://github.com/crystal-lang/crystal/pull/14887 [#14892]: https://github.com/crystal-lang/crystal/pull/14892 [#14842]: https://github.com/crystal-lang/crystal/pull/14842 [#14847]: https://github.com/crystal-lang/crystal/pull/14847 [#14890]: https://github.com/crystal-lang/crystal/pull/14890 [#11007]: https://github.com/crystal-lang/crystal/pull/11007 [#14729]: https://github.com/crystal-lang/crystal/pull/14729 [#14874]: https://github.com/crystal-lang/crystal/pull/14874 [#14834]: https://github.com/crystal-lang/crystal/pull/14834 [#14684]: https://github.com/crystal-lang/crystal/pull/14684 [#14796]: https://github.com/crystal-lang/crystal/pull/14796 [#14933]: https://github.com/crystal-lang/crystal/pull/14933 [#14945]: https://github.com/crystal-lang/crystal/pull/14945 [#14977]: https://github.com/crystal-lang/crystal/pull/14977 [#14822]: https://github.com/crystal-lang/crystal/pull/14822 [#14997]: https://github.com/crystal-lang/crystal/pull/14997 #### compiler - _(cli)_ Adds initial support for external commands ([#14953], thanks @bcardiff) - _(interpreter)_ Add `Crystal::Repl::Value#runtime_type` ([#14156], thanks @bcardiff) - _(interpreter)_ Implement `Reference.pre_initialize` in the interpreter ([#14968], thanks @HertzDevil) - _(interpreter)_ Enable the interpreter on Windows ([#14964], thanks @HertzDevil) [#14953]: https://github.com/crystal-lang/crystal/pull/14953 [#14156]: https://github.com/crystal-lang/crystal/pull/14156 [#14968]: https://github.com/crystal-lang/crystal/pull/14968 [#14964]: https://github.com/crystal-lang/crystal/pull/14964 ### Bugfixes #### lang - Fix `Slice.literal` for multiple calls with identical signature ([#15009], thanks @HertzDevil) - _(macros)_ Add location info to some `MacroIf` nodes ([#14885], thanks @Blacksmoke16) [#15009]: https://github.com/crystal-lang/crystal/pull/15009 [#14885]: https://github.com/crystal-lang/crystal/pull/14885 #### stdlib - _(collection)_ Fix `Range#size` return type to `Int32` ([#14588], thanks @straight-shoota) - _(concurrency)_ Update `DeallocationStack` for Windows context switch ([#15032], thanks @HertzDevil) - _(concurrency)_ Fix race condition in `pthread_create` handle initialization ([#15043], thanks @HertzDevil) - _(files)_ **[regression]** Fix `File#truncate` and `#lock` for Win32 append-mode files ([#14706], thanks @HertzDevil) - _(files)_ **[breaking]** Avoid flush in finalizers for `Socket` and `IO::FileDescriptor` ([#14882], thanks @straight-shoota) - _(files)_ Make `IO::Buffered#buffer_size=` idempotent ([#14855], thanks @jgaskins) - _(macros)_ Implement `#sort_by` inside macros using `Enumerable#sort_by` ([#14895], thanks @HertzDevil) - _(macros)_ Fix internal error when calling `#is_a?` on `External` nodes ([#14918], thanks @HertzDevil) - _(networking)_ Use correct timeout for `Socket#connect` on Windows ([#14961], thanks @HertzDevil) - _(numeric)_ Fix handle empty string in `String#to_f(whitespace: false)` ([#14902], thanks @Blacksmoke16) - _(numeric)_ Fix exponent wrapping in `Math.frexp(BigFloat)` for very large values ([#14971], thanks @HertzDevil) - _(numeric)_ Fix exponent overflow in `BigFloat#to_s` for very large values ([#14982], thanks @HertzDevil) - _(numeric)_ Add missing `@[Link(dll:)]` annotation to MPIR ([#15003], thanks @HertzDevil) - _(runtime)_ Add missing return type of `LibC.VirtualQuery` ([#15036], thanks @HertzDevil) - _(runtime)_ Fix main stack top detection on musl-libc ([#15047], thanks @HertzDevil) - _(serialization)_ **[breaking]** Remove `XML::Error.errors` ([#14936], thanks @straight-shoota) - _(specs)_ **[regression]** Fix `Expectations::Be` for module type ([#14926], thanks @straight-shoota) - _(system)_ Fix return type restriction for `ENV.fetch` ([#14919], thanks @straight-shoota) - _(system)_ `#file_descriptor_close` should set `@closed` (UNIX) ([#14973], thanks @ysbaddaden) - _(system)_ reinit event loop first after fork (UNIX) ([#14975], thanks @ysbaddaden) - _(text)_ Fix avoid linking `libpcre` when unused ([#14891], thanks @kojix2) - _(text)_ Add type restriction to `String#byte_index` `offset` parameter ([#14981], thanks @straight-shoota) [#14588]: https://github.com/crystal-lang/crystal/pull/14588 [#15032]: https://github.com/crystal-lang/crystal/pull/15032 [#15043]: https://github.com/crystal-lang/crystal/pull/15043 [#14706]: https://github.com/crystal-lang/crystal/pull/14706 [#14882]: https://github.com/crystal-lang/crystal/pull/14882 [#14855]: https://github.com/crystal-lang/crystal/pull/14855 [#14895]: https://github.com/crystal-lang/crystal/pull/14895 [#14918]: https://github.com/crystal-lang/crystal/pull/14918 [#14961]: https://github.com/crystal-lang/crystal/pull/14961 [#14902]: https://github.com/crystal-lang/crystal/pull/14902 [#14971]: https://github.com/crystal-lang/crystal/pull/14971 [#14982]: https://github.com/crystal-lang/crystal/pull/14982 [#15003]: https://github.com/crystal-lang/crystal/pull/15003 [#15036]: https://github.com/crystal-lang/crystal/pull/15036 [#15047]: https://github.com/crystal-lang/crystal/pull/15047 [#14936]: https://github.com/crystal-lang/crystal/pull/14936 [#14926]: https://github.com/crystal-lang/crystal/pull/14926 [#14919]: https://github.com/crystal-lang/crystal/pull/14919 [#14973]: https://github.com/crystal-lang/crystal/pull/14973 [#14975]: https://github.com/crystal-lang/crystal/pull/14975 [#14891]: https://github.com/crystal-lang/crystal/pull/14891 [#14981]: https://github.com/crystal-lang/crystal/pull/14981 #### compiler - _(cli)_ Add error handling for linker flag sub commands ([#14932], thanks @straight-shoota) - _(codegen)_ Allow returning `Proc`s from top-level funs ([#14917], thanks @HertzDevil) - _(codegen)_ Fix CRT static-dynamic linking conflict in specs with C sources ([#14970], thanks @HertzDevil) - _(interpreter)_ Fix Linux `getrandom` failure in interpreted code ([#15035], thanks @HertzDevil) - _(interpreter)_ Fix undefined behavior in interpreter mixed union upcast ([#15042], thanks @HertzDevil) - _(semantic)_ Fix `TopLevelVisitor` adding existing `ClassDef` type to current scope ([#15067], thanks @straight-shoota) [#14932]: https://github.com/crystal-lang/crystal/pull/14932 [#14917]: https://github.com/crystal-lang/crystal/pull/14917 [#14970]: https://github.com/crystal-lang/crystal/pull/14970 [#15035]: https://github.com/crystal-lang/crystal/pull/15035 [#15042]: https://github.com/crystal-lang/crystal/pull/15042 [#15067]: https://github.com/crystal-lang/crystal/pull/15067 #### tools - _(dependencies)_ Fix `crystal tool dependencies` format flat ([#14927], thanks @straight-shoota) - _(dependencies)_ Fix `crystal tool dependencies` filters for Windows paths ([#14928], thanks @straight-shoota) - _(docs-generator)_ Fix doc comment above annotation with macro expansion ([#14849], thanks @Blacksmoke16) - _(unreachable)_ Fix `crystal tool unreachable` & co visiting circular hierarchies ([#15065], thanks @straight-shoota) [#14927]: https://github.com/crystal-lang/crystal/pull/14927 [#14928]: https://github.com/crystal-lang/crystal/pull/14928 [#14849]: https://github.com/crystal-lang/crystal/pull/14849 [#15065]: https://github.com/crystal-lang/crystal/pull/15065 ### Chores #### stdlib - **[deprecation]** Use `Time::Span` in `Benchmark.ips` ([#14805], thanks @HertzDevil) - **[deprecation]** Deprecate `::sleep(Number)` ([#14962], thanks @HertzDevil) - _(runtime)_ **[deprecation]** Deprecate `Pointer.new(Int)` ([#14875], thanks @straight-shoota) [#14805]: https://github.com/crystal-lang/crystal/pull/14805 [#14962]: https://github.com/crystal-lang/crystal/pull/14962 [#14875]: https://github.com/crystal-lang/crystal/pull/14875 #### compiler - _(interpreter)_ Remove TODO in `Crystal::Loader` on Windows ([#14988], thanks @HertzDevil) - _(interpreter:repl)_ Update REPLy version ([#14950], thanks @HertzDevil) [#14988]: https://github.com/crystal-lang/crystal/pull/14988 [#14950]: https://github.com/crystal-lang/crystal/pull/14950 ### Performance #### stdlib - _(collection)_ Always use unstable sort for simple types ([#14825], thanks @HertzDevil) - _(collection)_ Optimize `Hash#transform_{keys,values}` ([#14502], thanks @jgaskins) - _(numeric)_ Optimize arithmetic between `BigFloat` and integers ([#14944], thanks @HertzDevil) - _(runtime)_ **[regression]** Cache `Exception::CallStack.empty` to avoid repeat `Array` allocation ([#15025], thanks @straight-shoota) [#14825]: https://github.com/crystal-lang/crystal/pull/14825 [#14502]: https://github.com/crystal-lang/crystal/pull/14502 [#14944]: https://github.com/crystal-lang/crystal/pull/14944 [#15025]: https://github.com/crystal-lang/crystal/pull/15025 #### compiler - Avoid unwinding the stack on hot path in method call lookups ([#15002], thanks @ggiraldez) - _(codegen)_ Reduce calls to `Crystal::Type#remove_indirection` in module dispatch ([#14992], thanks @HertzDevil) - _(codegen)_ Compiler: enable parallel codegen with MT ([#14748], thanks @ysbaddaden) [#15002]: https://github.com/crystal-lang/crystal/pull/15002 [#14992]: https://github.com/crystal-lang/crystal/pull/14992 [#14748]: https://github.com/crystal-lang/crystal/pull/14748 ### Refactor #### stdlib - _(concurrency)_ Extract `select` from `src/channel.cr` ([#14912], thanks @straight-shoota) - _(concurrency)_ Make `Crystal::IOCP::OverlappedOperation` abstract ([#14987], thanks @HertzDevil) - _(files)_ Move `#evented_read`, `#evented_write` into `Crystal::LibEvent::EventLoop` ([#14883], thanks @straight-shoota) - _(networking)_ Simplify `Socket::Addrinfo.getaddrinfo(&)` ([#14956], thanks @HertzDevil) - _(networking)_ Add `Crystal::System::Addrinfo` ([#14957], thanks @HertzDevil) - _(runtime)_ Add `Exception::CallStack.empty` ([#15017], thanks @straight-shoota) - _(system)_ Refactor cancellation of `IOCP::OverlappedOperation` ([#14754], thanks @straight-shoota) - _(system)_ Include `Crystal::System::Group` instead of extending it ([#14930], thanks @HertzDevil) - _(system)_ Include `Crystal::System::User` instead of extending it ([#14929], thanks @HertzDevil) - _(system)_ Fix: `Crystal::SpinLock` doesn't need to be allocated on the HEAP ([#14972], thanks @ysbaddaden) - _(system)_ Don't involve evloop after fork in `System::Process.spawn` (UNIX) ([#14974], thanks @ysbaddaden) - _(system)_ Refactor `EventLoop` interface for sleeps & select timeouts ([#14980], thanks @ysbaddaden) [#14912]: https://github.com/crystal-lang/crystal/pull/14912 [#14987]: https://github.com/crystal-lang/crystal/pull/14987 [#14883]: https://github.com/crystal-lang/crystal/pull/14883 [#14956]: https://github.com/crystal-lang/crystal/pull/14956 [#14957]: https://github.com/crystal-lang/crystal/pull/14957 [#15017]: https://github.com/crystal-lang/crystal/pull/15017 [#14754]: https://github.com/crystal-lang/crystal/pull/14754 [#14930]: https://github.com/crystal-lang/crystal/pull/14930 [#14929]: https://github.com/crystal-lang/crystal/pull/14929 [#14972]: https://github.com/crystal-lang/crystal/pull/14972 [#14974]: https://github.com/crystal-lang/crystal/pull/14974 [#14980]: https://github.com/crystal-lang/crystal/pull/14980 #### compiler - _(codegen)_ Compiler: refactor codegen ([#14760], thanks @ysbaddaden) - _(interpreter)_ Refactor interpreter stack code to avoid duplicate macro expansion ([#14876], thanks @straight-shoota) [#14760]: https://github.com/crystal-lang/crystal/pull/14760 [#14876]: https://github.com/crystal-lang/crystal/pull/14876 ### Documentation #### stdlib - _(collection)_ **[breaking]** Hide `Hash::Entry` from public API docs ([#14881], thanks @Blacksmoke16) - _(collection)_ Fix typos in docs for `Set` and `Hash` ([#14889], thanks @philipp-classen) - _(llvm)_ Add `@[Experimental]` to `LLVM::DIBuilder` ([#14854], thanks @HertzDevil) - _(networking)_ Add documentation about synchronous DNS resolution ([#15027], thanks @straight-shoota) - _(networking)_ Add `uri/json` to `docs_main` ([#15069], thanks @straight-shoota) - _(runtime)_ Add docs about `Pointer`'s alignment requirement ([#14853], thanks @HertzDevil) - _(runtime)_ Reword `Pointer#memcmp`'s documentation ([#14818], thanks @HertzDevil) - _(runtime)_ Add documentation for `NoReturn` and `Void` ([#14817], thanks @nobodywasishere) [#14881]: https://github.com/crystal-lang/crystal/pull/14881 [#14889]: https://github.com/crystal-lang/crystal/pull/14889 [#14854]: https://github.com/crystal-lang/crystal/pull/14854 [#15027]: https://github.com/crystal-lang/crystal/pull/15027 [#15069]: https://github.com/crystal-lang/crystal/pull/15069 [#14853]: https://github.com/crystal-lang/crystal/pull/14853 [#14818]: https://github.com/crystal-lang/crystal/pull/14818 [#14817]: https://github.com/crystal-lang/crystal/pull/14817 ### Specs #### stdlib - Remove some uses of deprecated overloads in standard library specs ([#14963], thanks @HertzDevil) - _(collection)_ Disable `Tuple#to_static_array` spec on AArch64 ([#14844], thanks @HertzDevil) - _(serialization)_ Add JSON parsing UTF-8 spec ([#14823], thanks @Blacksmoke16) - _(text)_ Add specs for `String#index`, `#rindex` search for `Char::REPLACEMENT` ([#14946], thanks @straight-shoota) [#14963]: https://github.com/crystal-lang/crystal/pull/14963 [#14844]: https://github.com/crystal-lang/crystal/pull/14844 [#14823]: https://github.com/crystal-lang/crystal/pull/14823 [#14946]: https://github.com/crystal-lang/crystal/pull/14946 #### compiler - _(codegen)_ Support return types in codegen specs ([#14888], thanks @HertzDevil) - _(codegen)_ Fix codegen spec for `ProcPointer` of virtual type ([#14903], thanks @HertzDevil) - _(codegen)_ Support LLVM OrcV2 codegen specs ([#14886], thanks @HertzDevil) - _(codegen)_ Don't spawn subprocess if codegen spec uses flags but not the prelude ([#14904], thanks @HertzDevil) [#14888]: https://github.com/crystal-lang/crystal/pull/14888 [#14903]: https://github.com/crystal-lang/crystal/pull/14903 [#14886]: https://github.com/crystal-lang/crystal/pull/14886 [#14904]: https://github.com/crystal-lang/crystal/pull/14904 ### Infrastructure - Changelog for 1.14.0 ([#14969], thanks @straight-shoota) - Update previous Crystal release 1.13.1 ([#14810], thanks @straight-shoota) - Refactor GitHub changelog generator print special infra ([#14795], thanks @straight-shoota) - Update distribution-scripts ([#14877], thanks @straight-shoota) - Update version in `shard.yml` ([#14909], thanks @straight-shoota) - Merge `release/1.13`@1.13.2 ([#14924], thanks @straight-shoota) - Update previous Crystal release 1.13.2 ([#14925], thanks @straight-shoota) - Merge `release/1.13`@1.13.3 ([#15012], thanks @straight-shoota) - Update previous Crystal release 1.13.3 ([#15016], thanks @straight-shoota) - **[regression]** Fix `SOURCE_DATE_EPOCH` in `Makefile.win` ([#14922], thanks @HertzDevil) - _(ci)_ Update actions/checkout action to v4 - autoclosed ([#14896], thanks @renovate) - _(ci)_ Update LLVM 18 for `wasm32-test` ([#14821], thanks @straight-shoota) - _(ci)_ Pin package repos for OpenSSL packages ([#14831], thanks @straight-shoota) - _(ci)_ Upgrade XCode 15.4.0 ([#14794], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#14535], thanks @renovate) - _(ci)_ Add test for OpenSSL 3.3 ([#14873], thanks @straight-shoota) - _(ci)_ Update GitHub runner to `macos-14` ([#14833], thanks @straight-shoota) - _(ci)_ Refactor SSL workflow with job matrix ([#14899], thanks @straight-shoota) - _(ci)_ Drop the non-release Windows compiler artifact ([#15000], thanks @HertzDevil) - _(ci)_ Fix compiler artifact name in WindowsCI ([#15021], thanks @straight-shoota) - _(ci)_ Restrict CI runners from runs-on to 8GB ([#15030], thanks @straight-shoota) - _(ci)_ Increase memory for stdlib CI runners from runs-on to 16GB ([#15044], thanks @straight-shoota) - _(ci)_ Use Cygwin to build libiconv on Windows CI ([#14999], thanks @HertzDevil) - _(ci)_ Use our own `libffi` repository on Windows CI ([#14998], thanks @HertzDevil) [#14969]: https://github.com/crystal-lang/crystal/pull/14969 [#14810]: https://github.com/crystal-lang/crystal/pull/14810 [#14795]: https://github.com/crystal-lang/crystal/pull/14795 [#14877]: https://github.com/crystal-lang/crystal/pull/14877 [#14909]: https://github.com/crystal-lang/crystal/pull/14909 [#14924]: https://github.com/crystal-lang/crystal/pull/14924 [#14925]: https://github.com/crystal-lang/crystal/pull/14925 [#15012]: https://github.com/crystal-lang/crystal/pull/15012 [#15016]: https://github.com/crystal-lang/crystal/pull/15016 [#14922]: https://github.com/crystal-lang/crystal/pull/14922 [#14896]: https://github.com/crystal-lang/crystal/pull/14896 [#14821]: https://github.com/crystal-lang/crystal/pull/14821 [#14831]: https://github.com/crystal-lang/crystal/pull/14831 [#14794]: https://github.com/crystal-lang/crystal/pull/14794 [#14535]: https://github.com/crystal-lang/crystal/pull/14535 [#14873]: https://github.com/crystal-lang/crystal/pull/14873 [#14833]: https://github.com/crystal-lang/crystal/pull/14833 [#14899]: https://github.com/crystal-lang/crystal/pull/14899 [#15000]: https://github.com/crystal-lang/crystal/pull/15000 [#15021]: https://github.com/crystal-lang/crystal/pull/15021 [#15030]: https://github.com/crystal-lang/crystal/pull/15030 [#15044]: https://github.com/crystal-lang/crystal/pull/15044 [#14999]: https://github.com/crystal-lang/crystal/pull/14999 [#14998]: https://github.com/crystal-lang/crystal/pull/14998 ================================================ FILE: doc/changelogs/v1.15.md ================================================ # Changelog 1.15 ## [1.15.1] (2025-02-04) [1.15.1]: https://github.com/crystal-lang/crystal/releases/1.15.1 ### Bugfixes #### stdlib - _(networking)_ Disable directory path redirect when `directory_listing=false` ([#15393], thanks @straight-shoota) - _(runtime)_ **[regression]** abstract `EventLoop::Polling#system_add` invalid signature ([#15380], backported from [#15358], thanks @straight-shoota) - _(system)_ **[regression]** Fix GC `sig_suspend`, `sig_resume` for `gc_none` ([#15382], backported from [#15349], thanks @ysbaddaden) [#15393]: https://github.com/crystal-lang/crystal/pull/15393 [#15380]: https://github.com/crystal-lang/crystal/pull/15380 [#15358]: https://github.com/crystal-lang/crystal/pull/15358 [#15382]: https://github.com/crystal-lang/crystal/pull/15382 [#15349]: https://github.com/crystal-lang/crystal/pull/15349 ### Documentation #### stdlib - _(system)_ Fix code example in `Process::Status#exit_code` docs ([#15381], backported from [#15351], thanks @zw963) [#15381]: https://github.com/crystal-lang/crystal/pull/15381 [#15351]: https://github.com/crystal-lang/crystal/pull/15351 ### Infrastructure - Changelog for 1.15.1 ([#15406], thanks @straight-shoota) - Update distribution-scripts ([#15385], backported from [#15368], thanks @straight-shoota) - Update distribution-scripts ([#15388], thanks @straight-shoota) - _(ci)_ Add build shards to `mingw-w64` workflow ([#15344], thanks @straight-shoota) - _(ci)_ Update shards 0.19.1 ([#15384], backported from [#15366], thanks @straight-shoota) - _(ci)_ Add check for shards binary in `test_dist_linux_on_docker` ([#15394], thanks @straight-shoota) [#15406]: https://github.com/crystal-lang/crystal/pull/15406 [#15385]: https://github.com/crystal-lang/crystal/pull/15385 [#15368]: https://github.com/crystal-lang/crystal/pull/15368 [#15388]: https://github.com/crystal-lang/crystal/pull/15388 [#15344]: https://github.com/crystal-lang/crystal/pull/15344 [#15384]: https://github.com/crystal-lang/crystal/pull/15384 [#15366]: https://github.com/crystal-lang/crystal/pull/15366 [#15394]: https://github.com/crystal-lang/crystal/pull/15394 ## [1.15.0] (2025-01-09) [1.15.0]: https://github.com/crystal-lang/crystal/releases/1.15.0 ### Breaking changes #### lang - Allow constants to start with non-ascii uppercase and titlecase ([#15148], thanks @nanobowers) [#15148]: https://github.com/crystal-lang/crystal/pull/15148 ### Features #### lang - _(macros)_ Crystal `Not` operators do not need parens for stringification ([#15292], thanks @Blacksmoke16) - _(macros)_ Add `MacroIf#is_unless?` AST node method ([#15304], thanks @Blacksmoke16) [#15292]: https://github.com/crystal-lang/crystal/pull/15292 [#15304]: https://github.com/crystal-lang/crystal/pull/15304 #### stdlib - _(collection)_ Add `Iterator(T).empty` ([#15039], thanks @spuun) - _(collection)_ Add `Enumerable#find_value` ([#14893], thanks @jgaskins) - _(concurrency)_ Implement the ARM64 Windows context switch ([#15155], thanks @HertzDevil) - _(concurrency)_ Add optional `name` parameter forward to `WaitGroup#spawn` ([#15189], thanks @spuun) - _(crypto)_ Enable bindings for functions in LibreSSL ([#15177], thanks @straight-shoota) - _(log)_ Add `Log` overloads for logging exceptions without giving a block ([#15257], thanks @lachlan) - _(networking)_ Better handle explicit chunked encoding responses ([#15092], thanks @Blacksmoke16) - _(networking)_ Support OpenSSL on MSYS2 ([#15111], thanks @HertzDevil) - _(networking)_ Add `Socket::Address.from` without `addrlen` ([#15060], thanks @mamantoha) - _(networking)_ Add stringification for `HTTP::Cookie` ([#15240], thanks @straight-shoota) - _(networking)_ Add stringification for `HTTP::Cookies` ([#15246], thanks @straight-shoota) - _(networking)_ Add `HTTP::Cookie#expire` ([#14819], thanks @a-alhusaini) - _(numeric)_ Implement `fast_float` for `String#to_f` ([#15195], thanks @HertzDevil) - _(runtime)_ Support call stacks for MinGW-w64 builds ([#15117], thanks @HertzDevil) - _(runtime)_ Support MSYS2's CLANGARM64 environment on ARM64 Windows ([#15159], thanks @HertzDevil) - _(runtime)_ Improve `Crystal::Tracing` ([#15297], thanks @ysbaddaden) - _(runtime)_ Add `Thread#internal_name=` ([#15298], thanks @ysbaddaden) - _(runtime)_ Add `Thread::LinkedList#each` to safely iterate lists ([#15300], thanks @ysbaddaden) - _(system)_ Add `Process::Status#exit_code?` ([#15247], thanks @straight-shoota) - _(system)_ Add `Process::Status#abnormal_exit?` ([#15266], thanks @straight-shoota) - _(system)_ Improve `Process::Status#to_s` for abnormal exits on Windows ([#15283], thanks @straight-shoota) - _(system)_ Add `Process::Status#exit_signal?` ([#15284], thanks @straight-shoota) - _(system)_ Change `Process::Status#to_s` to hex format on Windows ([#15285], thanks @straight-shoota) - _(system)_ Add `Process::Status#system_exit_status` ([#15296], thanks @straight-shoota) - _(text)_ Add `Regex::CompileOptions::MULTILINE_ONLY` ([#14870], thanks @ralsina) - _(text)_ Add type restrictions to Levenshtein ([#15168], thanks @beta-ziliani) - _(text)_ Add `unit_separator` to `Int#humanize` and `#humanize_bytes` ([#15176], thanks @CTC97) - _(text)_ Add `String#byte_index(Regex)` ([#15248], thanks @Zeljko-Predjeskovic) - _(text)_ Add `Colorize::Object#ansi_escape` ([#15113], thanks @devnote-dev) [#15039]: https://github.com/crystal-lang/crystal/pull/15039 [#14893]: https://github.com/crystal-lang/crystal/pull/14893 [#15155]: https://github.com/crystal-lang/crystal/pull/15155 [#15189]: https://github.com/crystal-lang/crystal/pull/15189 [#15177]: https://github.com/crystal-lang/crystal/pull/15177 [#15257]: https://github.com/crystal-lang/crystal/pull/15257 [#15092]: https://github.com/crystal-lang/crystal/pull/15092 [#15111]: https://github.com/crystal-lang/crystal/pull/15111 [#15060]: https://github.com/crystal-lang/crystal/pull/15060 [#15240]: https://github.com/crystal-lang/crystal/pull/15240 [#15246]: https://github.com/crystal-lang/crystal/pull/15246 [#14819]: https://github.com/crystal-lang/crystal/pull/14819 [#15195]: https://github.com/crystal-lang/crystal/pull/15195 [#15117]: https://github.com/crystal-lang/crystal/pull/15117 [#15159]: https://github.com/crystal-lang/crystal/pull/15159 [#15297]: https://github.com/crystal-lang/crystal/pull/15297 [#15298]: https://github.com/crystal-lang/crystal/pull/15298 [#15300]: https://github.com/crystal-lang/crystal/pull/15300 [#15247]: https://github.com/crystal-lang/crystal/pull/15247 [#15266]: https://github.com/crystal-lang/crystal/pull/15266 [#15283]: https://github.com/crystal-lang/crystal/pull/15283 [#15284]: https://github.com/crystal-lang/crystal/pull/15284 [#15285]: https://github.com/crystal-lang/crystal/pull/15285 [#15296]: https://github.com/crystal-lang/crystal/pull/15296 [#14870]: https://github.com/crystal-lang/crystal/pull/14870 [#15168]: https://github.com/crystal-lang/crystal/pull/15168 [#15176]: https://github.com/crystal-lang/crystal/pull/15176 [#15248]: https://github.com/crystal-lang/crystal/pull/15248 [#15113]: https://github.com/crystal-lang/crystal/pull/15113 #### compiler - Basic MinGW-w64 cross-compilation support ([#15070], [#15219], thanks @HertzDevil, @BlobCodes) - _(cli)_ Support building from a MinGW-w64-based compiler ([#15077], thanks @HertzDevil) - _(codegen)_ Add indirect branch tracking ([#15122], thanks @ysbaddaden) - _(codegen)_ Emit position dependent code for embedded targets ([#15174], thanks @RX14) - _(interpreter)_ Support "long format" DLL import libraries ([#15119], thanks @HertzDevil) - _(interpreter)_ Add `cc`'s search paths to Unix dynamic library loader ([#15127], thanks @HertzDevil) - _(interpreter)_ Basic MinGW-w64-based interpreter support ([#15140], thanks @HertzDevil) - _(parser)_ Add `ECR::Lexer::SyntaxException` with location info ([#15222], thanks @nobodywasishere) [#15070]: https://github.com/crystal-lang/crystal/pull/15070 [#15219]: https://github.com/crystal-lang/crystal/pull/15219 [#15077]: https://github.com/crystal-lang/crystal/pull/15077 [#15122]: https://github.com/crystal-lang/crystal/pull/15122 [#15174]: https://github.com/crystal-lang/crystal/pull/15174 [#15119]: https://github.com/crystal-lang/crystal/pull/15119 [#15127]: https://github.com/crystal-lang/crystal/pull/15127 [#15140]: https://github.com/crystal-lang/crystal/pull/15140 [#15222]: https://github.com/crystal-lang/crystal/pull/15222 #### tools - _(formatter)_ Enable pending formatter features ([#14718], thanks @Blacksmoke16) - _(unreachable)_ Implement `codecov` format for `unreachable` tool ([#15059], thanks @Blacksmoke16) [#14718]: https://github.com/crystal-lang/crystal/pull/14718 [#15059]: https://github.com/crystal-lang/crystal/pull/15059 ### Bugfixes #### lang - _(macros)_ Add location information to more MacroIf related nodes ([#15100], thanks @Blacksmoke16) [#15100]: https://github.com/crystal-lang/crystal/pull/15100 #### stdlib - LibC bindings and std specs on NetBSD 10 ([#15115], thanks @ysbaddaden) - _(files)_ Treat `WinError::ERROR_DIRECTORY` as an error for non-existent files ([#15114], thanks @HertzDevil) - _(files)_ Replace handle atomically in `IO::FileDescriptor#close` on Windows ([#15165], thanks @HertzDevil) - _(llvm)_ Fix `find-llvm-config` to ignore `LLVM_CONFIG`'s escape sequences ([#15076], thanks @HertzDevil) - _(log)_ **[regression]** Fix `Log` to emit with `exception` even if block outputs `nil` ([#15253], thanks @lachlan) - _(macros)_ Avoid identifier naming collision in `getter`, `setter`, and `property` macros ([#15239], thanks @jgaskins) - _(networking)_ **[regression]** Fix `UNIXSocket#receive` ([#15107], thanks @straight-shoota) - _(numeric)_ Fix `Complex#/` edge cases ([#15086], thanks @HertzDevil) - _(numeric)_ Fix `Number#humanize` printing of `(-)Infinity` and `NaN` ([#15090], thanks @lachlan) - _(runtime)_ Fix Deadlock with parallel stop-world/fork calls in MT ([#15096], thanks @ysbaddaden) - _(runtime)_ **[regression]** Protect constant initializers with mutex on Windows ([#15134], thanks @HertzDevil) - _(runtime)_ use `uninitialized LibC::SigsetT` ([#15144], thanks @straight-shoota) - _(runtime)_ Fix static linking when using MinGW-w64 ([#15167], thanks @HertzDevil) - _(runtime)_ register GC callbacks inside `GC.init` ([#15278], thanks @ysbaddaden) - _(runtime)_ Cleanup nodes in `Thread::LinkedList(T)#delete` ([#15295], thanks @ysbaddaden) - _(runtime)_ Make `Crystal::EventLoop#remove(io)` a class method ([#15282], thanks @ysbaddaden) - _(system)_ Raise on abnormal exit in `Process::Status#exit_code` ([#15241], thanks @straight-shoota) - _(system)_ Fix `Process::Status` for unknown signals ([#15280], thanks @straight-shoota) - _(system)_ Fix error handling for `LibC.clock_gettime(CLOCK_MONOTONIC)` calls ([#15309], thanks @compumike) - _(text)_ Fix libiconv build on Windows ([#15095], thanks @HertzDevil) - _(text)_ Change `sprintf "%c"` to support only `Char` and `Int::Primitive` ([#15142], thanks @nanobowers) - _(time)_ Fix proper error handling for early end in `HTTP_DATE` parser ([#15232], thanks @straight-shoota) [#15115]: https://github.com/crystal-lang/crystal/pull/15115 [#15114]: https://github.com/crystal-lang/crystal/pull/15114 [#15165]: https://github.com/crystal-lang/crystal/pull/15165 [#15076]: https://github.com/crystal-lang/crystal/pull/15076 [#15253]: https://github.com/crystal-lang/crystal/pull/15253 [#15239]: https://github.com/crystal-lang/crystal/pull/15239 [#15107]: https://github.com/crystal-lang/crystal/pull/15107 [#15086]: https://github.com/crystal-lang/crystal/pull/15086 [#15090]: https://github.com/crystal-lang/crystal/pull/15090 [#15096]: https://github.com/crystal-lang/crystal/pull/15096 [#15134]: https://github.com/crystal-lang/crystal/pull/15134 [#15144]: https://github.com/crystal-lang/crystal/pull/15144 [#15167]: https://github.com/crystal-lang/crystal/pull/15167 [#15278]: https://github.com/crystal-lang/crystal/pull/15278 [#15295]: https://github.com/crystal-lang/crystal/pull/15295 [#15282]: https://github.com/crystal-lang/crystal/pull/15282 [#15241]: https://github.com/crystal-lang/crystal/pull/15241 [#15280]: https://github.com/crystal-lang/crystal/pull/15280 [#15309]: https://github.com/crystal-lang/crystal/pull/15309 [#15095]: https://github.com/crystal-lang/crystal/pull/15095 [#15142]: https://github.com/crystal-lang/crystal/pull/15142 [#15232]: https://github.com/crystal-lang/crystal/pull/15232 #### compiler - OpenBSD: fix integration and broken specs ([#15118], thanks @ysbaddaden) - _(interpreter)_ setup signal handlers in interpreted code ([#14766], [#15178], thanks @ysbaddaden, @straight-shoota) - _(parser)_ Fix `SyntaxHighlighter` delimiter state ([#15104], thanks @straight-shoota) - _(parser)_ Disallow weird assignments ([#14815], thanks @FnControlOption) [#15118]: https://github.com/crystal-lang/crystal/pull/15118 [#14766]: https://github.com/crystal-lang/crystal/pull/14766 [#15178]: https://github.com/crystal-lang/crystal/pull/15178 [#15104]: https://github.com/crystal-lang/crystal/pull/15104 [#14815]: https://github.com/crystal-lang/crystal/pull/14815 #### tools - Improve man and shell completion for tools ([#15082], thanks @Blacksmoke16) - _(docs-generator)_ Fix first doc comment inside macro yield ([#15050], thanks @RX14) - _(implementations)_ Fix `tool implementations` to handle gracefully a def with missing location ([#15273], thanks @straight-shoota) [#15082]: https://github.com/crystal-lang/crystal/pull/15082 [#15050]: https://github.com/crystal-lang/crystal/pull/15050 [#15273]: https://github.com/crystal-lang/crystal/pull/15273 ### Chores #### stdlib - Fix various typos ([#15080], thanks @kojix2) - _(runtime)_ Make `Enum` an abstract struct ([#15274], thanks @straight-shoota) - _(system)_ **[deprecation]** Deprecate `Process::Status#exit_status` ([#8647], thanks @jwoertink) - _(system)_ Redefine `Process::Status#normal_exit?` on Windows ([#15255], [#15267], thanks @straight-shoota) - _(system)_ **[breaking]** Redefine `Process::Status#signal_exit?` ([#15289], thanks @straight-shoota) [#15080]: https://github.com/crystal-lang/crystal/pull/15080 [#15274]: https://github.com/crystal-lang/crystal/pull/15274 [#8647]: https://github.com/crystal-lang/crystal/pull/8647 [#15255]: https://github.com/crystal-lang/crystal/pull/15255 [#15267]: https://github.com/crystal-lang/crystal/pull/15267 [#15289]: https://github.com/crystal-lang/crystal/pull/15289 #### compiler - _(codegen)_ Link i128 constants internally if possible ([#15217], thanks @BlobCodes) - _(parser)_ Add location to `RegexLiteral` ([#15235], thanks @straight-shoota) [#15217]: https://github.com/crystal-lang/crystal/pull/15217 [#15235]: https://github.com/crystal-lang/crystal/pull/15235 ### Performance #### stdlib - _(collection)_ Optimize `Slice#<=>` and `#==` with reference check ([#15234], thanks @straight-shoota) - _(concurrency)_ Do not over-commit fiber stacks on Windows ([#15037], thanks @HertzDevil) - _(text)_ Pre-compute `String` size after `#chomp()` if possible ([#15153], thanks @HertzDevil) - _(text)_ Optimize `String#rchop?()` ([#15175], thanks @HertzDevil) - _(text)_ Optimize `String#==` taking character size into account ([#15233], thanks @straight-shoota) [#15234]: https://github.com/crystal-lang/crystal/pull/15234 [#15037]: https://github.com/crystal-lang/crystal/pull/15037 [#15153]: https://github.com/crystal-lang/crystal/pull/15153 [#15175]: https://github.com/crystal-lang/crystal/pull/15175 [#15233]: https://github.com/crystal-lang/crystal/pull/15233 #### compiler - _(semantic)_ Inline `ASTNode` bindings dependencies and observers ([#15098], thanks @ggiraldez) [#15098]: https://github.com/crystal-lang/crystal/pull/15098 ### Refactor #### stdlib - Use Win32 heap functions with `-Dgc_none` ([#15173], thanks @HertzDevil) - _(collection)_ Refactor `Enumerable#map` to delegate to `#map_with_index` ([#15210], thanks @straight-shoota) - _(concurrency)_ Drop `Crystal::FiberChannel` ([#15245], thanks @ysbaddaden) - _(runtime)_ Refactor uses of `LibC.dladdr` inside `Exception::CallStack` ([#15108], thanks @HertzDevil) - _(runtime)_ Introduce `Crystal::EventLoop` namespace ([#15226], thanks @ysbaddaden) - _(runtime)_ Change `libevent` event loop to wait forever when blocking ([#15243], thanks @ysbaddaden) - _(runtime)_ Refactor the IOCP event loop (timers, ...) ([#15238], thanks @ysbaddaden) - _(runtime)_ Explicit exit from main ([#15299], thanks @ysbaddaden) - _(serialization)_ Use per-thread libxml2 global state on all platforms ([#15121], thanks @HertzDevil) - _(system)_ Assume `getrandom` on Linux ([#15040], thanks @ysbaddaden) - _(system)_ Refactor Lifetime Event Loop ([#14996], [#15205], [#15206], [#15215], [#15301], thanks @ysbaddaden) - _(system)_ Refactor use of `Process::Status#exit_code` to `#exit_code?` ([#15254], thanks @straight-shoota) - _(system)_ Refactor simplify `Process::Status#exit_reason` on Unix ([#15288], thanks @straight-shoota) [#15173]: https://github.com/crystal-lang/crystal/pull/15173 [#15210]: https://github.com/crystal-lang/crystal/pull/15210 [#15245]: https://github.com/crystal-lang/crystal/pull/15245 [#15108]: https://github.com/crystal-lang/crystal/pull/15108 [#15226]: https://github.com/crystal-lang/crystal/pull/15226 [#15243]: https://github.com/crystal-lang/crystal/pull/15243 [#15238]: https://github.com/crystal-lang/crystal/pull/15238 [#15299]: https://github.com/crystal-lang/crystal/pull/15299 [#15121]: https://github.com/crystal-lang/crystal/pull/15121 [#15040]: https://github.com/crystal-lang/crystal/pull/15040 [#14996]: https://github.com/crystal-lang/crystal/pull/14996 [#15205]: https://github.com/crystal-lang/crystal/pull/15205 [#15206]: https://github.com/crystal-lang/crystal/pull/15206 [#15215]: https://github.com/crystal-lang/crystal/pull/15215 [#15301]: https://github.com/crystal-lang/crystal/pull/15301 [#15254]: https://github.com/crystal-lang/crystal/pull/15254 [#15288]: https://github.com/crystal-lang/crystal/pull/15288 #### compiler - _(semantic)_ Replace uses of `AliasType#types?` by `Type#lookup_name` ([#15068], thanks @straight-shoota) [#15068]: https://github.com/crystal-lang/crystal/pull/15068 ### Documentation #### stdlib - Add docs for lib bindings with supported library versions ([#14900], [#15198], thanks @straight-shoota) - _(concurrency)_ Make `Fiber.timeout` and `.cancel_timeout` nodoc ([#15184], thanks @straight-shoota) - _(concurrency)_ Update example code for `::spawn` with `WaitGroup` ([#15191], thanks @BigBoyBarney) - _(numeric)_ Clarify behavior of `strict` for `String`-to-number conversions ([#15199], thanks @HertzDevil) - _(runtime)_ Make `Box` constructor and `object` getter nodoc ([#15136], thanks @straight-shoota) - _(runtime)_ Fix `EventLoop` docs for `Socket` `read`, `write` ([#15194], thanks @straight-shoota) - _(system)_ Add example for `Dir.glob` ([#15171], thanks @BigBoyBarney) - _(system)_ Adjust definition of `ExitReason::Aborted` ([#15256], thanks @straight-shoota) - _(text)_ Improve docs for `String#rindex!` ([#15132], thanks @BigBoyBarney) - _(text)_ Add note about locale-dependent system error messages ([#15196], thanks @HertzDevil) [#14900]: https://github.com/crystal-lang/crystal/pull/14900 [#15198]: https://github.com/crystal-lang/crystal/pull/15198 [#15184]: https://github.com/crystal-lang/crystal/pull/15184 [#15191]: https://github.com/crystal-lang/crystal/pull/15191 [#15199]: https://github.com/crystal-lang/crystal/pull/15199 [#15136]: https://github.com/crystal-lang/crystal/pull/15136 [#15194]: https://github.com/crystal-lang/crystal/pull/15194 [#15171]: https://github.com/crystal-lang/crystal/pull/15171 [#15256]: https://github.com/crystal-lang/crystal/pull/15256 [#15132]: https://github.com/crystal-lang/crystal/pull/15132 [#15196]: https://github.com/crystal-lang/crystal/pull/15196 ### Specs #### stdlib - Fix failing specs on FreeBSD ([#15093], thanks @ysbaddaden) - Disable specs that break on MinGW-w64 ([#15116], thanks @HertzDevil) - _(networking)_ DragonFlyBSD: std specs fixes + pending ([#15152], thanks @ysbaddaden) - _(networking)_ Close some dangling sockets in specs ([#15163], thanks @HertzDevil) - _(networking)_ Update specs to run with IPv6 support disabled ([#15046], thanks @Blacksmoke16) - _(networking)_ Add specs for invalid special characters in `Cookie` ([#15244], thanks @straight-shoota) - _(system)_ Improve `System::User` specs on Windows ([#15156], thanks @HertzDevil) - _(system)_ Make `cmd.exe` drop `%PROCESSOR_ARCHITECTURE%` in `Process` specs ([#15158], thanks @HertzDevil) - _(system)_ Add specs for signal exit ([#15229], thanks @straight-shoota) [#15093]: https://github.com/crystal-lang/crystal/pull/15093 [#15116]: https://github.com/crystal-lang/crystal/pull/15116 [#15152]: https://github.com/crystal-lang/crystal/pull/15152 [#15163]: https://github.com/crystal-lang/crystal/pull/15163 [#15046]: https://github.com/crystal-lang/crystal/pull/15046 [#15244]: https://github.com/crystal-lang/crystal/pull/15244 [#15156]: https://github.com/crystal-lang/crystal/pull/15156 [#15158]: https://github.com/crystal-lang/crystal/pull/15158 [#15229]: https://github.com/crystal-lang/crystal/pull/15229 #### compiler - _(cli)_ Remove the entire compiler code base from `external_command_spec` ([#15208], thanks @straight-shoota) - _(interpreter)_ **[regression]** Fix `Crystal::Loader.default_search_paths` spec for macOS ([#15135], thanks @HertzDevil) [#15208]: https://github.com/crystal-lang/crystal/pull/15208 [#15135]: https://github.com/crystal-lang/crystal/pull/15135 #### tools - Use empty prelude for compiler tools specs ([#15272], thanks @straight-shoota) - _(docs-generator)_ Allow skipping compiler tool specs that require Git ([#15125], thanks @HertzDevil) [#15272]: https://github.com/crystal-lang/crystal/pull/15272 [#15125]: https://github.com/crystal-lang/crystal/pull/15125 ### Infrastructure - Changelog for 1.15.0 ([#15277], thanks @straight-shoota) - Update previous Crystal release 1.14.0 ([#15071], thanks @straight-shoota) - Fix remove trailing whitespace from CRYSTAL definition ([#15131], thanks @straight-shoota) - Make utilities posix compatible ([#15139], thanks @nanobowers) - Update `shell.nix` to `nixpkgs-24.05` and LLVM 18 ([#14651], thanks @straight-shoota) - Makefile: Allow custom extensions for exports and spec flags ([#15099], thanks @straight-shoota) - Merge changelog entries for fixups with main PR ([#15207], thanks @straight-shoota) - Update link to good first issues ([#15250], thanks @BigBoyBarney) - Update distribution-scripts ([#15291], thanks @straight-shoota) - Bump NOTICE copyright year ([#15318], thanks @straight-shoota) - Merge `release/1.14`@1.14.1 ([#15329], thanks @straight-shoota) - Update distribution-scripts ([#15332], thanks @straight-shoota) - Make `bin/crystal` work on MSYS2 ([#15094], thanks @HertzDevil) - Make `Makefile` work on MSYS2 ([#15102], thanks @HertzDevil) - Support `.exe` file extension in `Makefile` on MSYS2 ([#15123], thanks @HertzDevil) - Support dereferencing symlinks in `make install` ([#15138], thanks @HertzDevil) - _(ci)_ Extract `deploy_api_docs` job into its own Workflow ([#15022], thanks @straight-shoota) - _(ci)_ Remove pin for ancient nix version ([#15150], thanks @straight-shoota) - _(ci)_ Migrate renovate config ([#15151], thanks @renovate) - _(ci)_ Update GH Actions ([#15052], thanks @renovate) - _(ci)_ Update msys2/setup-msys2 action to v2.26.0 ([#15265], thanks @renovate) - _(ci)_ Update shards 0.19.0 ([#15290], thanks @straight-shoota) - _(ci)_ **[security]** Restrict GitHub token permissions of CI workflows ([#15087], thanks @HertzDevil) - _(ci)_ Do not link against `DbgHelp` for MinGW-w64 CI build ([#15160], thanks @HertzDevil) - _(ci)_ Use MSYS2's upstream LLVM version on MinGW-w64 CI ([#15197], thanks @HertzDevil) - _(ci)_ Add CI workflow for cross-compiling Crystal on MSYS2 ([#15110], thanks @HertzDevil) - _(ci)_ Add MinGW-w64 CI workflow for stdlib and compiler specs ([#15124], thanks @HertzDevil) - _(ci)_ Make MinGW-w64 build artifact a full installation ([#15204], thanks @HertzDevil) - _(ci)_ Use official Apt repositories for LLVM CI ([#15103], thanks @HertzDevil) - _(ci)_ Drop LLVM Apt installer script on WebAssembly CI ([#15109], thanks @HertzDevil) - _(ci)_ Run interpreter specs on Windows CI ([#15141], thanks @HertzDevil) [#15277]: https://github.com/crystal-lang/crystal/pull/15277 [#15071]: https://github.com/crystal-lang/crystal/pull/15071 [#15131]: https://github.com/crystal-lang/crystal/pull/15131 [#15139]: https://github.com/crystal-lang/crystal/pull/15139 [#14651]: https://github.com/crystal-lang/crystal/pull/14651 [#15099]: https://github.com/crystal-lang/crystal/pull/15099 [#15207]: https://github.com/crystal-lang/crystal/pull/15207 [#15250]: https://github.com/crystal-lang/crystal/pull/15250 [#15291]: https://github.com/crystal-lang/crystal/pull/15291 [#15318]: https://github.com/crystal-lang/crystal/pull/15318 [#15329]: https://github.com/crystal-lang/crystal/pull/15329 [#15332]: https://github.com/crystal-lang/crystal/pull/15332 [#15094]: https://github.com/crystal-lang/crystal/pull/15094 [#15102]: https://github.com/crystal-lang/crystal/pull/15102 [#15123]: https://github.com/crystal-lang/crystal/pull/15123 [#15138]: https://github.com/crystal-lang/crystal/pull/15138 [#15022]: https://github.com/crystal-lang/crystal/pull/15022 [#15150]: https://github.com/crystal-lang/crystal/pull/15150 [#15151]: https://github.com/crystal-lang/crystal/pull/15151 [#15052]: https://github.com/crystal-lang/crystal/pull/15052 [#15265]: https://github.com/crystal-lang/crystal/pull/15265 [#15290]: https://github.com/crystal-lang/crystal/pull/15290 [#15087]: https://github.com/crystal-lang/crystal/pull/15087 [#15160]: https://github.com/crystal-lang/crystal/pull/15160 [#15197]: https://github.com/crystal-lang/crystal/pull/15197 [#15110]: https://github.com/crystal-lang/crystal/pull/15110 [#15124]: https://github.com/crystal-lang/crystal/pull/15124 [#15204]: https://github.com/crystal-lang/crystal/pull/15204 [#15103]: https://github.com/crystal-lang/crystal/pull/15103 [#15109]: https://github.com/crystal-lang/crystal/pull/15109 [#15141]: https://github.com/crystal-lang/crystal/pull/15141 ================================================ FILE: doc/changelogs/v1.16.md ================================================ # Changelog 1.16 ## [1.16.3] (2025-05-12) [1.16.3]: https://github.com/crystal-lang/crystal/releases/1.16.3 ### Bugfixes #### stdlib - _(runtime)_ Fix `Crystal::EventLoop::LibEvent` and `FiberExecutionContext` integration ([#15759], backported from [#15743], thanks @ysbaddaden) [#15759]: https://github.com/crystal-lang/crystal/pull/15759 [#15743]: https://github.com/crystal-lang/crystal/pull/15743 #### compiler - _(codegen)_ Add fallback if `__crystal_raise_cast_failed` is missing ([#15769], backported from [#15762], thanks @HertzDevil) - _(semantic)_ **[regression]** Remove type binding on `T` for `Pointer(T)#value=` ([#15757], backported from [#15751], thanks @HertzDevil) [#15769]: https://github.com/crystal-lang/crystal/pull/15769 [#15762]: https://github.com/crystal-lang/crystal/pull/15762 [#15757]: https://github.com/crystal-lang/crystal/pull/15757 [#15751]: https://github.com/crystal-lang/crystal/pull/15751 ### Infrastructure - Changelog for 1.16.3 ([#15758], thanks @straight-shoota) [#15758]: https://github.com/crystal-lang/crystal/pull/15758 ## [1.16.2] (2025-04-29) [1.16.2]: https://github.com/crystal-lang/crystal/releases/1.16.2 ### Bugfixes #### stdlib - _(numeric)_ Fix show `unit_separator` in `#humanize_bytes` with empty prefix ([#15717], backported from [#15683], thanks @straight-shoota) - _(runtime)_ `CRYSTAL_LOAD_DEBUG_INFO=1` fails with `-Dexecution_context` ([#15715], backported from [#15704], thanks @ysbaddaden) - _(runtime)_ Fix `-Dtracing` raises math overflows on fiber sleep ([#15725], backported from [#15722], thanks @ysbaddaden) - _(runtime)_ Fix `Fiber::ExecutionContext::Isolated#wait` must suspend fiber ([#15723], backported from [#15720], thanks @ysbaddaden) - _(runtime)_ Fix run win32 console reader in bare thread ([#15726], backported from [#15724], thanks @ysbaddaden) [#15717]: https://github.com/crystal-lang/crystal/pull/15717 [#15683]: https://github.com/crystal-lang/crystal/pull/15683 [#15715]: https://github.com/crystal-lang/crystal/pull/15715 [#15704]: https://github.com/crystal-lang/crystal/pull/15704 [#15725]: https://github.com/crystal-lang/crystal/pull/15725 [#15722]: https://github.com/crystal-lang/crystal/pull/15722 [#15723]: https://github.com/crystal-lang/crystal/pull/15723 [#15720]: https://github.com/crystal-lang/crystal/pull/15720 [#15726]: https://github.com/crystal-lang/crystal/pull/15726 [#15724]: https://github.com/crystal-lang/crystal/pull/15724 #### compiler - _(semantic)_ Do not add `ReferenceStorage` to `Value`'s subclasses twice ([#15718], backported from [#15706], thanks @HertzDevil) [#15718]: https://github.com/crystal-lang/crystal/pull/15718 [#15706]: https://github.com/crystal-lang/crystal/pull/15706 ### Refactor #### compiler - _(codegen)_ Add `__crystal_raise_cast_failed` for non-interpreted code ([#15712], backported from [#15708], thanks @HertzDevil) [#15712]: https://github.com/crystal-lang/crystal/pull/15712 [#15708]: https://github.com/crystal-lang/crystal/pull/15708 ### Infrastructure - Changelog for 1.16.2 ([#15716], thanks @straight-shoota) - _(ci)_ Fix package shards on MinGW ([#15719], thanks @straight-shoota) - _(ci)_ Only set up Cygwin on Windows CI if truly required ([#15713], backported from [#15661], thanks @HertzDevil) [#15716]: https://github.com/crystal-lang/crystal/pull/15716 [#15719]: https://github.com/crystal-lang/crystal/pull/15719 [#15713]: https://github.com/crystal-lang/crystal/pull/15713 [#15661]: https://github.com/crystal-lang/crystal/pull/15661 ## [1.16.1] (2025-04-16) [1.16.1]: https://github.com/crystal-lang/crystal/releases/1.16.1 ### Bugfixes #### stdlib - _(runtime)_ Correctly transfer FD ownership in polling event loop ([#15650], thanks @ysbaddaden) - _(runtime)_ Fix error message when `PollDescriptor` can't transfer fd ([#15663], thanks @ysbaddaden) - _(runtime)_ Fix `libgc` pkg-config name for version discovery ([#15636], thanks @straight-shoota) - _(serialization)_ **[regression]** Fix link `bcrypt` with `libxml2` on Windows ([#15651], thanks @straight-shoota) [#15650]: https://github.com/crystal-lang/crystal/pull/15650 [#15663]: https://github.com/crystal-lang/crystal/pull/15663 [#15636]: https://github.com/crystal-lang/crystal/pull/15636 [#15651]: https://github.com/crystal-lang/crystal/pull/15651 #### compiler - _(cli)_ **[regression]** Fix `crystal eval` read from stdin ([#15655], thanks @straight-shoota) [#15655]: https://github.com/crystal-lang/crystal/pull/15655 ### Documentation #### stdlib - _(runtime)_ Enable docs for `ExecutionContext` ([#15644], thanks @straight-shoota) - _(runtime)_ Fix mark method overrides on `ExecutionContext` as `:nodoc:` ([#15659], thanks @ysbaddaden) - _(runtime)_ Update docs for `Fiber::ExecutionContext.default_workers_count` ([#15664], thanks @ysbaddaden) - _(runtime)_ Enhance documentation for `ExecutionContext` ([#15665], thanks @straight-shoota) [#15644]: https://github.com/crystal-lang/crystal/pull/15644 [#15659]: https://github.com/crystal-lang/crystal/pull/15659 [#15664]: https://github.com/crystal-lang/crystal/pull/15664 [#15665]: https://github.com/crystal-lang/crystal/pull/15665 ### Infrastructure - Changelog for 1.16.1 ([#15666], thanks @straight-shoota) [#15666]: https://github.com/crystal-lang/crystal/pull/15666 ## [1.16.0] (2025-04-09) [1.16.0]: https://github.com/crystal-lang/crystal/releases/1.16.0 ### Features #### lang - Support `Slice.literal` in the interpreter ([#15531], thanks @HertzDevil) - Support `Slice.literal` with inferred element type ([#15529], thanks @HertzDevil) - _(macros)_ Error on `TypeNode#instance_vars`, `#has_inner_pointers?` macros in top-level scope ([#15293], thanks @straight-shoota) - _(macros)_ Support `sizeof` and `alignof` inside macros for stable types ([#15497], thanks @HertzDevil) [#15531]: https://github.com/crystal-lang/crystal/pull/15531 [#15529]: https://github.com/crystal-lang/crystal/pull/15529 [#15293]: https://github.com/crystal-lang/crystal/pull/15293 [#15497]: https://github.com/crystal-lang/crystal/pull/15497 #### stdlib - Fix `Box(Pointer).box` to not allocate pointer storage on the heap ([#15562], thanks @ysbaddaden) - _(collection)_ Add `Indexable#find` and `#find!` ([#15552], [#15589], thanks @punteek, @Sija) - _(llvm)_ Add `LLVM.version` ([#15354], thanks @straight-shoota) - _(llvm)_ Support LLVM 20 ([#15412], [#15418], thanks @HertzDevil, @straight-shoota) - _(llvm)_ Add `LLVM.init_native_target` and `LLVM.init_all_targets` ([#15466], thanks @HertzDevil) - _(llvm)_ Support `$LLVM_VERSION`, `$LLVM_TARGETS`, and `$LLVM_LDFLAGS` ([#15091], thanks @HertzDevil) - _(llvm)_ Add `LLVM::CodeModel::Tiny` ([#15608], thanks @HertzDevil) - _(macros)_ Implement `StringLiteral#scan` ([#15398], thanks @homonoidian) - _(networking)_ Add `Path` as possible argument type to `UNIXSocket` and `UNIXServer` ([#15260], thanks @BigBoyBarney) - _(networking)_ Add `Cookies#==` ([#15463], thanks @straight-shoota) - _(runtime)_ Add `EventLoop#wait_readable`, `#wait_writable` methods methods ([#15376], thanks @ysbaddaden) - _(runtime)_ Initialize `Fiber` with an explicit stack ([#15409], thanks @ysbaddaden) - _(runtime)_ Add fiber queues for execution context schedulers ([#15345], thanks @ysbaddaden) - _(runtime)_ RFC 2: Skeleton for ExecutionContext ([#15350], [#15596], thanks @ysbaddaden) - _(runtime)_ RFC 2: Add `Fiber::ExecutionContext::SingleThreaded` scheduler ([#15511], thanks @ysbaddaden) - _(runtime)_ RFC 2: Add `Fiber::ExecutionContext::Isolated` ([#15513], thanks @ysbaddaden) - _(runtime)_ RFC 2: Add `Fiber::ExecutionContext::Monitor` ([#15599], thanks @ysbaddaden) - _(runtime)_ RFC 2: Add `Fiber::ExecutionContext::MultiThreaded` ([#15517], thanks @ysbaddaden) - _(serialization)_ Add `Union.from_json_object_key?` ([#15411], thanks @straight-shoota) - _(system)_ Add `Process::Status#description` ([#15468], thanks @straight-shoota) - _(text)_ Add `IO` overloads to `Char#upcase`, `#downcase`, `#titlecase` ([#15508], thanks @HertzDevil) - _(text)_ **[breaking]** New algorithm for `File.match?` ([#15607], thanks @straight-shoota) [#15562]: https://github.com/crystal-lang/crystal/pull/15562 [#15552]: https://github.com/crystal-lang/crystal/pull/15552 [#15589]: https://github.com/crystal-lang/crystal/pull/15589 [#15354]: https://github.com/crystal-lang/crystal/pull/15354 [#15412]: https://github.com/crystal-lang/crystal/pull/15412 [#15418]: https://github.com/crystal-lang/crystal/pull/15418 [#15466]: https://github.com/crystal-lang/crystal/pull/15466 [#15091]: https://github.com/crystal-lang/crystal/pull/15091 [#15608]: https://github.com/crystal-lang/crystal/pull/15608 [#15398]: https://github.com/crystal-lang/crystal/pull/15398 [#15260]: https://github.com/crystal-lang/crystal/pull/15260 [#15463]: https://github.com/crystal-lang/crystal/pull/15463 [#15376]: https://github.com/crystal-lang/crystal/pull/15376 [#15409]: https://github.com/crystal-lang/crystal/pull/15409 [#15345]: https://github.com/crystal-lang/crystal/pull/15345 [#15350]: https://github.com/crystal-lang/crystal/pull/15350 [#15596]: https://github.com/crystal-lang/crystal/pull/15596 [#15511]: https://github.com/crystal-lang/crystal/pull/15511 [#15513]: https://github.com/crystal-lang/crystal/pull/15513 [#15599]: https://github.com/crystal-lang/crystal/pull/15599 [#15517]: https://github.com/crystal-lang/crystal/pull/15517 [#15411]: https://github.com/crystal-lang/crystal/pull/15411 [#15468]: https://github.com/crystal-lang/crystal/pull/15468 [#15508]: https://github.com/crystal-lang/crystal/pull/15508 [#15607]: https://github.com/crystal-lang/crystal/pull/15607 #### compiler - _(cli)_ Support `--output` long option in `crystal build` ([#15519], thanks @HertzDevil) - _(cli)_ Support directory name in `--output` CLI option ([#15471], thanks @straight-shoota) - _(cli)_ **[breaking]** Add compiler path to `$PATH` and `$CRYSTAL_EXEC_PATH` for subcommands ([#15186], thanks @straight-shoota) - _(cli)_ Respect `--mcpu=help` in the compiler ([#15595], thanks @HertzDevil) - _(cli)_ Add `CRYSTAL_EXEC_PATH` to `crystal env` [followup #15186] ([#15632], thanks @straight-shoota) - _(codegen)_ Set linkage of `__crystal_*` funs to internal ([#15439], thanks @ysbaddaden) - _(codegen)_ Add function name to `CRYSTAL_DEBUG_CODEGEN` log helper ([#15506], thanks @HertzDevil) - _(parser)_ Handle properly stringifying multiline macro expressions ([#15305], thanks @Blacksmoke16) - _(parser)_ **[breaking]** Check that def, macro, and block parameters don't end with `?` or `!` ([#12197], thanks @potomak) [#15519]: https://github.com/crystal-lang/crystal/pull/15519 [#15471]: https://github.com/crystal-lang/crystal/pull/15471 [#15186]: https://github.com/crystal-lang/crystal/pull/15186 [#15595]: https://github.com/crystal-lang/crystal/pull/15595 [#15632]: https://github.com/crystal-lang/crystal/pull/15632 [#15439]: https://github.com/crystal-lang/crystal/pull/15439 [#15506]: https://github.com/crystal-lang/crystal/pull/15506 [#15305]: https://github.com/crystal-lang/crystal/pull/15305 [#12197]: https://github.com/crystal-lang/crystal/pull/12197 #### tools - _(docs-generator)_ Add docs to enum member helper methods ([#15379], thanks @nobodywasishere) - _(docs-generator)_ Add `:showdoc:` directive for `private` and `protected` objects (RFC #0011) ([#15337], thanks @nobodywasishere) - _(docs-generator)_ Add documentation support for `lib`, `fun`, `union`, `cstruct`, `external`, and `type` (RFC #0011) ([#15447], thanks @nobodywasishere) [#15379]: https://github.com/crystal-lang/crystal/pull/15379 [#15337]: https://github.com/crystal-lang/crystal/pull/15337 [#15447]: https://github.com/crystal-lang/crystal/pull/15447 ### Bugfixes #### stdlib - _(collection)_ Fix hash `@indices` can grow larger than `Int32::MAX` bytes ([#15347], thanks @ysbaddaden) - _(collection)_ Fix `Tuple#to_a(&)` for arbitrary block output type ([#15431], thanks @straight-shoota) - _(collection)_ Fix `Range#size` for unsigned edge cases ([#14978], thanks @straight-shoota) - _(collection)_ **[breaking]** Fix the return type of `Enumerable#sum`, `#product` for union elements ([#15314], thanks @rvprasad) - _(concurrency)_ Fix `Reference#exec_recursive`, `#exec_recursive_clone` to be fiber aware ([#15361], thanks @ysbaddaden) - _(concurrency)_ RFC 2: MT safe fiber context switch on ARM ([#15582], thanks @ysbaddaden) - _(crypto)_ Fix argument type for `EVP_CIPHER_get_flags` ([#15392], thanks @miry) - _(files)_ Never remove UNC share name in `Path#dirname` ([#15583], thanks @HertzDevil) - _(files)_ Fix `File.exists?` for special devices on Windows ([#15587], thanks @HertzDevil) - _(llvm)_ Fix LLVM version detection for `-rc1` ([#15410], thanks @HertzDevil) - _(networking)_ **[breaking]** Fix parsing HTTP resource string that looks like absolute URL ([#15499], thanks @straight-shoota) - _(runtime)_ Fix `pkg_config` name for `libgc` bindings on FreeBSD ([#15532], thanks @straight-shoota) - _(runtime)_ RFC 2: MT safe fiber context switch on AArch64 ([#15581], thanks @ysbaddaden) - _(runtime)_ Add thread safety to `at_exit` ([#15598], thanks @ysbaddaden) - _(runtime)_ Remove top-level calls to `LibGC.has_method?` for backwards compat ([#15635], thanks @straight-shoota) - _(serialization)_ Fix `Union.from_yaml` to prioritize `String` for quoted scalar ([#15405], thanks @straight-shoota) - _(system)_ signal handler mustn't depend on the event loop ([#15325], thanks @ysbaddaden) - _(system)_ Corrects Windows lib lookup in case-sensitive OSes ([#15362], thanks @luislavena) - _(system)_ Fix permissions application in `File.copy` ([#15520], thanks @straight-shoota) - _(system)_ **[security]** Strip periods, spaces for batch file filtering on Windows ([#15573], thanks @GeopJr) - _(system)_ Extend Windows `Process` completion key's lifetime ([#15597], thanks @HertzDevil) [#15347]: https://github.com/crystal-lang/crystal/pull/15347 [#15431]: https://github.com/crystal-lang/crystal/pull/15431 [#14978]: https://github.com/crystal-lang/crystal/pull/14978 [#15314]: https://github.com/crystal-lang/crystal/pull/15314 [#15361]: https://github.com/crystal-lang/crystal/pull/15361 [#15582]: https://github.com/crystal-lang/crystal/pull/15582 [#15392]: https://github.com/crystal-lang/crystal/pull/15392 [#15583]: https://github.com/crystal-lang/crystal/pull/15583 [#15587]: https://github.com/crystal-lang/crystal/pull/15587 [#15410]: https://github.com/crystal-lang/crystal/pull/15410 [#15499]: https://github.com/crystal-lang/crystal/pull/15499 [#15532]: https://github.com/crystal-lang/crystal/pull/15532 [#15581]: https://github.com/crystal-lang/crystal/pull/15581 [#15598]: https://github.com/crystal-lang/crystal/pull/15598 [#15635]: https://github.com/crystal-lang/crystal/pull/15635 [#15405]: https://github.com/crystal-lang/crystal/pull/15405 [#15325]: https://github.com/crystal-lang/crystal/pull/15325 [#15362]: https://github.com/crystal-lang/crystal/pull/15362 [#15520]: https://github.com/crystal-lang/crystal/pull/15520 [#15573]: https://github.com/crystal-lang/crystal/pull/15573 [#15597]: https://github.com/crystal-lang/crystal/pull/15597 #### compiler - _(cli)_ Fix query runtime version of LLVM ([#15355], thanks @straight-shoota) - _(cli)_ Fix handling of double dashes `--` in crystal `eval` command ([#15477], thanks @kojix2) - _(codegen)_ don't set external linkage when `@[NoInline]` is specified ([#15424], thanks @ysbaddaden) - _(codegen)_ Allow multiple redefinitions of the same top-level fun ([#15553], thanks @HertzDevil) - _(codegen)_ Respect `$MACOSX_DEPLOYMENT_TARGET` on macOS hosts ([#15603], thanks @HertzDevil) - _(interpreter)_ Fix `pkg_config` name for `libffi` bindings ([#15533], thanks @straight-shoota) - _(parser)_ Lexer: Fix location of token after line continuation ([#15454], thanks @FnControlOption) - _(parser)_ Add locations to `When` nodes ([#15481], thanks @Sija) - _(parser)_ Fix end location of call with block arg and no parentheses ([#15502], thanks @FnControlOption) - _(parser)_ Fix location of `MacroExpression` nodes ([#15524], thanks @Sija) - _(parser)_ Reject invalid operator names for implicit object calls ([#15526], thanks @nobodywasishere) [#15355]: https://github.com/crystal-lang/crystal/pull/15355 [#15477]: https://github.com/crystal-lang/crystal/pull/15477 [#15424]: https://github.com/crystal-lang/crystal/pull/15424 [#15553]: https://github.com/crystal-lang/crystal/pull/15553 [#15603]: https://github.com/crystal-lang/crystal/pull/15603 [#15533]: https://github.com/crystal-lang/crystal/pull/15533 [#15454]: https://github.com/crystal-lang/crystal/pull/15454 [#15481]: https://github.com/crystal-lang/crystal/pull/15481 [#15502]: https://github.com/crystal-lang/crystal/pull/15502 [#15524]: https://github.com/crystal-lang/crystal/pull/15524 [#15526]: https://github.com/crystal-lang/crystal/pull/15526 #### tools - _(formatter)_ Add uninitialized variables to formatter variable scopes ([#15578], thanks @HertzDevil) [#15578]: https://github.com/crystal-lang/crystal/pull/15578 ### Chores #### stdlib - _(llvm)_ **[breaking]** Remove the `LibLLVM::IS_*` constants ([#15464], thanks @HertzDevil) [#15464]: https://github.com/crystal-lang/crystal/pull/15464 #### compiler - _(interpreter:repl)_ Update REPLy version ([#15328], thanks @oprypin) [#15328]: https://github.com/crystal-lang/crystal/pull/15328 ### Performance #### stdlib - _(files)_ Optimize `Path#drive`, `#root`, and `#anchor` ([#15584], thanks @HertzDevil) - _(files)_ Optimize `Path#relative_to?` ([#15594], thanks @HertzDevil) - _(runtime)_ Shrink `Crystal::System.print_error`'s output size ([#15490], thanks @HertzDevil) [#15584]: https://github.com/crystal-lang/crystal/pull/15584 [#15594]: https://github.com/crystal-lang/crystal/pull/15594 [#15490]: https://github.com/crystal-lang/crystal/pull/15490 #### compiler - _(codegen)_ Replace inline type IDs with global constants in LLVM IR ([#15485], [#15505], thanks @HertzDevil) - _(codegen)_ Do not load `Path` call receiver if known to be pure load ([#15488], thanks @HertzDevil) - _(codegen)_ Only refer to LLVM symbol table in calls to `Symbol#to_s` ([#15486], thanks @HertzDevil) - _(debugger)_ Read all DWARF abbreviations tables in a single pass ([#15515], thanks @HertzDevil) - _(debugger)_ Use binary search to search DWARF line numbers ([#15539], thanks @HertzDevil) - _(debugger)_ Remove `op_index` and `end_sequence` from `Crystal::DWARF::LineNumbers::Row` ([#15538], thanks @HertzDevil) [#15485]: https://github.com/crystal-lang/crystal/pull/15485 [#15505]: https://github.com/crystal-lang/crystal/pull/15505 [#15488]: https://github.com/crystal-lang/crystal/pull/15488 [#15486]: https://github.com/crystal-lang/crystal/pull/15486 [#15515]: https://github.com/crystal-lang/crystal/pull/15515 [#15539]: https://github.com/crystal-lang/crystal/pull/15539 [#15538]: https://github.com/crystal-lang/crystal/pull/15538 ### Refactor #### stdlib - Use splat parameter to put `Tuple`s in large `Array` constants ([#15495], thanks @HertzDevil) - _(collection)_ Simplify `Enumerable#to_a` ([#15432], thanks @straight-shoota) - _(concurrency)_ Use `Crystal::PointerLinkedList` instead of `Deque` in `Mutex` ([#15330], thanks @ysbaddaden) - _(concurrency)_ Add fiber safety to crystal/once ([#15370], thanks @ysbaddaden) - _(concurrency)_ ARM: reduce duplication in fiber context switch ([#15585], thanks @ysbaddaden) - _(files)_ Add nanosecond precision to `File.utime` on Unix ([#15335], thanks @ysbaddaden) - _(llvm)_ **[deprecation]** Make `LLVM::ABI` internal ([#15559], thanks @HertzDevil) - _(llvm)_ Only initialize `LLVM::Attribute`'s class variables on demand ([#15534], thanks @HertzDevil) - _(macros)_ Generate Object getter/property macros to remove duplications ([#15386], thanks @ysbaddaden) - _(networking)_ Refactor extract `HTTP::Cookies` to its own file ([#15500], [#15618], thanks @straight-shoota) - _(runtime)_ Add `Crystal.print_buffered(io)` and `Crystal.print_error_buffered` ([#15343], thanks @ysbaddaden) - _(runtime)_ Explicit init of Thread and Fiber class variables ([#15369], thanks @ysbaddaden) - _(runtime)_ Add `Crystal.once_init` replacing `__crystal_once_init` ([#15371], thanks @ysbaddaden) - _(runtime)_ Move shadow space reservation to x86_64 makecontext ([#15434], thanks @ysbaddaden) - _(runtime)_ Add `Crystal::EventLoop#sleep(duration)` method ([#15564], thanks @ysbaddaden) - _(system)_ Extract `File.match?` to separate source file ([#15574], thanks @straight-shoota) [#15495]: https://github.com/crystal-lang/crystal/pull/15495 [#15432]: https://github.com/crystal-lang/crystal/pull/15432 [#15330]: https://github.com/crystal-lang/crystal/pull/15330 [#15370]: https://github.com/crystal-lang/crystal/pull/15370 [#15585]: https://github.com/crystal-lang/crystal/pull/15585 [#15335]: https://github.com/crystal-lang/crystal/pull/15335 [#15559]: https://github.com/crystal-lang/crystal/pull/15559 [#15534]: https://github.com/crystal-lang/crystal/pull/15534 [#15386]: https://github.com/crystal-lang/crystal/pull/15386 [#15500]: https://github.com/crystal-lang/crystal/pull/15500 [#15618]: https://github.com/crystal-lang/crystal/pull/15618 [#15343]: https://github.com/crystal-lang/crystal/pull/15343 [#15369]: https://github.com/crystal-lang/crystal/pull/15369 [#15371]: https://github.com/crystal-lang/crystal/pull/15371 [#15434]: https://github.com/crystal-lang/crystal/pull/15434 [#15564]: https://github.com/crystal-lang/crystal/pull/15564 [#15574]: https://github.com/crystal-lang/crystal/pull/15574 #### compiler - _(codegen)_ Rework initialization of constants & class variables ([#15333], thanks @ysbaddaden) - _(codegen)_ Remove unnecessary calls to `Crystal::CodeGenVisitor#union_type_and_value_pointer` ([#15491], thanks @HertzDevil) - _(parser)_ Simplify `Call.new` convenience overloads ([#15427], thanks @straight-shoota) - _(parser)_ Add `Call.new` constructor overload without `obj` parameter ([#15441], thanks @straight-shoota) - _(semantic)_ Extract `regex_value` helper for macro methods ([#15435], thanks @straight-shoota) [#15333]: https://github.com/crystal-lang/crystal/pull/15333 [#15491]: https://github.com/crystal-lang/crystal/pull/15491 [#15427]: https://github.com/crystal-lang/crystal/pull/15427 [#15441]: https://github.com/crystal-lang/crystal/pull/15441 [#15435]: https://github.com/crystal-lang/crystal/pull/15435 ### Documentation #### lang - Document `alignof` and `instance_alignof` ([#15576], thanks @HertzDevil) - _(macros)_ Document macro `sizeof` and `alignof` [followup #15497] ([#15575], thanks @HertzDevil) [#15576]: https://github.com/crystal-lang/crystal/pull/15576 [#15575]: https://github.com/crystal-lang/crystal/pull/15575 #### stdlib - Fix `Colorize::ObjectExtensions#colorize(r, g, b)` comment ([#15521], thanks @Sija) - Rework docs for `getter`, `setter` and `property` macros ([#15428], thanks @ysbaddaden) - Add missing files for API docs ([#15622], thanks @straight-shoota) - _(runtime)_ Document `::debugger` ([#15579], thanks @HertzDevil) [#15521]: https://github.com/crystal-lang/crystal/pull/15521 [#15428]: https://github.com/crystal-lang/crystal/pull/15428 [#15622]: https://github.com/crystal-lang/crystal/pull/15622 [#15579]: https://github.com/crystal-lang/crystal/pull/15579 #### compiler - _(cli)_ Convert `crystal.1` manpage to asciidoc ([#15478], thanks @straight-shoota) - _(cli)_ Split combined manpage into individual ones for each command ([#15509], thanks @straight-shoota) - _(cli)_ Document environment variable `CRYSTAL_EXEC_PATH` [followup #15186] ([#15631], thanks @straight-shoota) [#15478]: https://github.com/crystal-lang/crystal/pull/15478 [#15509]: https://github.com/crystal-lang/crystal/pull/15509 [#15631]: https://github.com/crystal-lang/crystal/pull/15631 #### other - Add sample fibonacci numbers ([#15550], thanks @666hwll) [#15550]: https://github.com/crystal-lang/crystal/pull/15550 ### Specs #### stdlib - Fix invalid returns in class getter's lazy evaluation blocks ([#15364], thanks @ysbaddaden) - _(specs)_ Add specs for `File.match?` ([#15348], thanks @straight-shoota) - _(text)_ Add specs for `File.match?` from fast-glob ([#15604], thanks @straight-shoota) - _(text)_ Add specs for `File.match?` with multibyte characters ([#15601], thanks @straight-shoota) [#15364]: https://github.com/crystal-lang/crystal/pull/15364 [#15348]: https://github.com/crystal-lang/crystal/pull/15348 [#15604]: https://github.com/crystal-lang/crystal/pull/15604 [#15601]: https://github.com/crystal-lang/crystal/pull/15601 #### compiler - _(parser)_ Add specs for block association in nested calls ([#15461], thanks @straight-shoota) [#15461]: https://github.com/crystal-lang/crystal/pull/15461 ### Infrastructure - Changelog for 1.16.0 ([#15602], thanks @straight-shoota) - Update previous Crystal release 1.15.0 ([#15339], thanks @straight-shoota) - Make: Fix `make uninstall` to remove fish completion ([#15367], thanks @straight-shoota) - Merge `release/1.15`@1.15.1 ([#15422], thanks @straight-shoota) - Fix: Remove reverted PR from changelog for 1.15.1 ([#15415], thanks @straight-shoota) - Update previous release: 1.15.1 ([#15417], thanks @straight-shoota) - Add backports to changelog generator ([#15413], thanks @straight-shoota) - Makefile: Expand `DESTDIR` outside of prefixed dir variables ([#15444], thanks @straight-shoota) - Add git mailmap ([#15396], thanks @straight-shoota) - Rename `find-llvm-config` to `find-llvm-config.sh` ([#15448], thanks @straight-shoota) - Makefile: Remove `crystal` from `DATADIR` ([#15467], thanks @straight-shoota) - Add `scripts/update-shards.sh` ([#15462], thanks @straight-shoota) - Enhance `.gitignore` ([#15469], thanks @straight-shoota) - Introduce shellcheck to lint shell scripts ([#15169], thanks @straight-shoota) - Trim `CHANGELOG.md` ([#15627], thanks @straight-shoota) - Update `scripts/generate_llvm_version_info.cr` ([#15465], thanks @HertzDevil) - _(ci)_ Fix shards packaging for mingw-w64 ([#15451], thanks @straight-shoota) - _(ci)_ Add workflow for backporting PRs to release branches ([#15372], [#15378], thanks @straight-shoota) - _(ci)_ Update cygwin/cygwin-install-action action to v5 ([#15346], thanks @renovate) - _(ci)_ Extract forward compatibility checks and run on nightly schedule ([#15437], thanks @straight-shoota) - _(ci)_ Use MSYS2 Crystal package for `mingw-w64` workflow ([#15453], [#15476], thanks @HertzDevil, @straight-shoota) - _(ci)_ Filter runs of LLVM Test workflow ([#15458], thanks @straight-shoota) - _(ci)_ Filter runs of regex engine workflow ([#15460], thanks @straight-shoota) - _(ci)_ Filter runs of OpenSSL Test workflow ([#15459], thanks @straight-shoota) - _(ci)_ Filter runs of Smoke Test workflow ([#15457], thanks @straight-shoota) - _(ci)_ Introduce actionlint to lint GitHub Actions workflows ([#15449], thanks @straight-shoota) - _(ci)_ Fix MinGW-W64 workflow to run compiler tests with fresh compiler ([#15522], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#15525], thanks @renovate) - _(ci)_ Update GH Actions ([#15551], thanks @renovate) - _(ci)_ Update library versions for MSVC CI ([#15554], thanks @HertzDevil) - _(ci)_ Increase memory for `aarch64-*-test-compiler` runners to 16GB ([#15572], thanks @straight-shoota) - _(ci)_ Add AArch64 Linux workflow using GitHub's runner ([#15600], thanks @HertzDevil) [#15602]: https://github.com/crystal-lang/crystal/pull/15602 [#15339]: https://github.com/crystal-lang/crystal/pull/15339 [#15367]: https://github.com/crystal-lang/crystal/pull/15367 [#15422]: https://github.com/crystal-lang/crystal/pull/15422 [#15415]: https://github.com/crystal-lang/crystal/pull/15415 [#15417]: https://github.com/crystal-lang/crystal/pull/15417 [#15413]: https://github.com/crystal-lang/crystal/pull/15413 [#15444]: https://github.com/crystal-lang/crystal/pull/15444 [#15396]: https://github.com/crystal-lang/crystal/pull/15396 [#15448]: https://github.com/crystal-lang/crystal/pull/15448 [#15467]: https://github.com/crystal-lang/crystal/pull/15467 [#15462]: https://github.com/crystal-lang/crystal/pull/15462 [#15469]: https://github.com/crystal-lang/crystal/pull/15469 [#15169]: https://github.com/crystal-lang/crystal/pull/15169 [#15627]: https://github.com/crystal-lang/crystal/pull/15627 [#15465]: https://github.com/crystal-lang/crystal/pull/15465 [#15451]: https://github.com/crystal-lang/crystal/pull/15451 [#15372]: https://github.com/crystal-lang/crystal/pull/15372 [#15378]: https://github.com/crystal-lang/crystal/pull/15378 [#15346]: https://github.com/crystal-lang/crystal/pull/15346 [#15437]: https://github.com/crystal-lang/crystal/pull/15437 [#15453]: https://github.com/crystal-lang/crystal/pull/15453 [#15476]: https://github.com/crystal-lang/crystal/pull/15476 [#15458]: https://github.com/crystal-lang/crystal/pull/15458 [#15460]: https://github.com/crystal-lang/crystal/pull/15460 [#15459]: https://github.com/crystal-lang/crystal/pull/15459 [#15457]: https://github.com/crystal-lang/crystal/pull/15457 [#15449]: https://github.com/crystal-lang/crystal/pull/15449 [#15522]: https://github.com/crystal-lang/crystal/pull/15522 [#15525]: https://github.com/crystal-lang/crystal/pull/15525 [#15551]: https://github.com/crystal-lang/crystal/pull/15551 [#15554]: https://github.com/crystal-lang/crystal/pull/15554 [#15572]: https://github.com/crystal-lang/crystal/pull/15572 [#15600]: https://github.com/crystal-lang/crystal/pull/15600 ================================================ FILE: doc/changelogs/v1.17.md ================================================ # Changelog 1.17 ## [1.17.1] (2025-07-22) [1.17.1]: https://github.com/crystal-lang/crystal/releases/1.17.1 ### Bugfixes #### tools - _(docs-generator)_ **[regression]** Revert "Handle doc locations when file is in parent directory" ([#15996], thanks @Blacksmoke16) [#15996]: https://github.com/crystal-lang/crystal/pull/15996 ### Infrastructure - Changelog for 1.17.1 ([#16009], thanks @straight-shoota) [#16009]: https://github.com/crystal-lang/crystal/pull/16009 ## [1.17.0] (2025-07-16) [1.17.0]: https://github.com/crystal-lang/crystal/releases/1.17.0 ### Breaking changes #### stdlib - Make `Colorize.on_tty_only!` the default behavior ([#15881], thanks @HertzDevil) - _(concurrency)_ Rename execution contexts + improve their docs ([#15936], thanks @ysbaddaden) - _(files)_ Refactor `IO.pipe` blocking mode ([#15823], thanks @ysbaddaden) - _(files)_ Fix: set `IO::Stapled.pipe` blocking args to nil, as per `IO.pipe` ([#15925], thanks @ysbaddaden) - _(networking)_ Refactor `Socket` blocking mode ([#15804], thanks @ysbaddaden) - _(runtime)_ Let the event loop decide the blocking mode of `File` ([#15930], thanks @ysbaddaden) - _(serialization)_ Fix: libxml manual memory management ([#15906], [#15933], thanks @ysbaddaden) - _(system)_ Turn `SystemError.from_errno` into a macro ([#15874], thanks @straight-shoota) [#15881]: https://github.com/crystal-lang/crystal/pull/15881 [#15936]: https://github.com/crystal-lang/crystal/pull/15936 [#15823]: https://github.com/crystal-lang/crystal/pull/15823 [#15925]: https://github.com/crystal-lang/crystal/pull/15925 [#15804]: https://github.com/crystal-lang/crystal/pull/15804 [#15930]: https://github.com/crystal-lang/crystal/pull/15930 [#15906]: https://github.com/crystal-lang/crystal/pull/15906 [#15933]: https://github.com/crystal-lang/crystal/pull/15933 [#15874]: https://github.com/crystal-lang/crystal/pull/15874 ### Features #### lang - _(macros)_ Handle properly stringifying single line blocks ([#15568], thanks @Blacksmoke16) - _(macros)_ Handle properly stringifying multiline named tuple literals ([#15566], thanks @Blacksmoke16) - _(macros)_ Handle properly stringifying multiline calls ([#15691], thanks @Blacksmoke16) - _(macros)_ Handle significant whitespace before a blocks body ([#15692], thanks @Blacksmoke16) - _(macros)_ Support `{% if ...; end; ... %}` macro expressions ([#15917], thanks @HertzDevil) - _(macros)_ Support `{% elsif %}` when stringifying `MacroIf` nodes ([#15928], thanks @HertzDevil) [#15568]: https://github.com/crystal-lang/crystal/pull/15568 [#15566]: https://github.com/crystal-lang/crystal/pull/15566 [#15691]: https://github.com/crystal-lang/crystal/pull/15691 [#15692]: https://github.com/crystal-lang/crystal/pull/15692 [#15917]: https://github.com/crystal-lang/crystal/pull/15917 [#15928]: https://github.com/crystal-lang/crystal/pull/15928 #### stdlib - Add `Colorize.default_enabled?` ([#15912], thanks @HertzDevil) - **[experimental]** Add `Struct.pre_initialize` ([#15896], thanks @HertzDevil) - _(files)_ Support Windows local device paths in `Path` ([#15590], thanks @HertzDevil) - _(llvm)_ Support LLVM 21.0 (development branch) ([#15771], thanks @HertzDevil) - _(networking)_ Extract `WebSocket#do_ping`, `#do_close` helper methods for overrides ([#15545], thanks @luislavena) - _(networking)_ Add support for IPv6 scoped addresses (RFC4007) ([#15263], thanks @foxxx0) - _(networking)_ Expose `HTTP::Request#uri` ([#15816], thanks @syeopite) - _(numeric)_ Add `BigRational#to_i` ([#15809], thanks @HertzDevil) - _(numeric)_ Add `Float::Primitive#sign_bit` ([#15830], thanks @HertzDevil) - _(runtime)_ Add explicit `Crystal::EventLoop#reopened(FileDescriptor)` hook ([#15640], thanks @ysbaddaden) - _(runtime)_ Add `Crystal::EventLoop::FileDescriptor#open` ([#15750], thanks @ysbaddaden) - _(runtime)_ Add `Thread::Local(T)` ([#15616], thanks @ysbaddaden) - _(serialization)_ Add `XML.libxml2_version` ([#15623], thanks @straight-shoota) - _(serialization)_ Add `YAML::Builder#start_document(*, implicit_start_indicator)` ([#15835], thanks @straight-shoota) - _(serialization)_ Support pretty printing of `XML` types ([#15833], thanks @HertzDevil) - _(serialization)_ Expose error message from libyaml on emitter errors ([#15841], thanks @straight-shoota) - _(serialization)_ Add `Path.from_json_object_key` ([#15877], thanks @jneen) - _(serialization)_ Add `Time::Location#{to,from}_{json,yaml}` ([#15939], thanks @Sija) - _(serialization)_ Extract `XML::Document` from `XML::Node` ([#15920], thanks @ysbaddaden) - _(text)_ **[experimental]** Add `Crystal::System.wstr_literal` on Windows ([#15747], thanks @HertzDevil) - _(text)_ Add `String#ensure_suffix` and `String#ensure_prefix` ([#15782], thanks @MatheusRich) - _(text)_ Add `truncate_at_null` parameter to `String.new(Bytes)` and `.from_utf16` ([#15887], thanks @HertzDevil) - _(time)_ Add `Time.month_week_date` ([#15620], thanks @HertzDevil) - _(time)_ Improve the TZif database file parser ([#15825], thanks @HertzDevil) - _(time)_ Support POSIX TZ environment variable strings ([#15792], thanks @HertzDevil) - _(time)_ Improve whitespace handling in `Time::Format` ([#15890], thanks @HertzDevil) - _(time)_ Support Windows system time zone transitions in all years ([#15891], thanks @HertzDevil) - _(time)_ Support POSIX TZ strings in TZif databases ([#15863], thanks @HertzDevil) [#15912]: https://github.com/crystal-lang/crystal/pull/15912 [#15896]: https://github.com/crystal-lang/crystal/pull/15896 [#15590]: https://github.com/crystal-lang/crystal/pull/15590 [#15771]: https://github.com/crystal-lang/crystal/pull/15771 [#15545]: https://github.com/crystal-lang/crystal/pull/15545 [#15263]: https://github.com/crystal-lang/crystal/pull/15263 [#15816]: https://github.com/crystal-lang/crystal/pull/15816 [#15809]: https://github.com/crystal-lang/crystal/pull/15809 [#15830]: https://github.com/crystal-lang/crystal/pull/15830 [#15640]: https://github.com/crystal-lang/crystal/pull/15640 [#15750]: https://github.com/crystal-lang/crystal/pull/15750 [#15616]: https://github.com/crystal-lang/crystal/pull/15616 [#15623]: https://github.com/crystal-lang/crystal/pull/15623 [#15835]: https://github.com/crystal-lang/crystal/pull/15835 [#15833]: https://github.com/crystal-lang/crystal/pull/15833 [#15841]: https://github.com/crystal-lang/crystal/pull/15841 [#15877]: https://github.com/crystal-lang/crystal/pull/15877 [#15939]: https://github.com/crystal-lang/crystal/pull/15939 [#15920]: https://github.com/crystal-lang/crystal/pull/15920 [#15747]: https://github.com/crystal-lang/crystal/pull/15747 [#15782]: https://github.com/crystal-lang/crystal/pull/15782 [#15887]: https://github.com/crystal-lang/crystal/pull/15887 [#15620]: https://github.com/crystal-lang/crystal/pull/15620 [#15825]: https://github.com/crystal-lang/crystal/pull/15825 [#15792]: https://github.com/crystal-lang/crystal/pull/15792 [#15890]: https://github.com/crystal-lang/crystal/pull/15890 [#15891]: https://github.com/crystal-lang/crystal/pull/15891 [#15863]: https://github.com/crystal-lang/crystal/pull/15863 #### compiler - _(cli)_ Support `--x86-asm-syntax` for emitting Intel style assembly ([#15612], thanks @HertzDevil) - _(debugger)_ Support debug info of 128-bit enum members ([#15770], thanks @HertzDevil) - _(parser)_ More robust trailing expressions newline implementation ([#15614], thanks @Blacksmoke16) - _(parser)_ Handle properly stringifying multiline (boolean) expressions ([#15709], thanks @Blacksmoke16) - _(parser)_ Stringify `MacroIf` `unless` nodes properly ([#15919], thanks @HertzDevil) - _(parser)_ Support `elsif` when stringifying `If` nodes ([#15918], thanks @HertzDevil) - _(parser)_ Add location info to `MacroVar` nodes ([#15947], thanks @Blacksmoke16) - _(semantic)_ Improve error message for `pointerof` ([#15876], thanks @straight-shoota) [#15612]: https://github.com/crystal-lang/crystal/pull/15612 [#15770]: https://github.com/crystal-lang/crystal/pull/15770 [#15614]: https://github.com/crystal-lang/crystal/pull/15614 [#15709]: https://github.com/crystal-lang/crystal/pull/15709 [#15919]: https://github.com/crystal-lang/crystal/pull/15919 [#15918]: https://github.com/crystal-lang/crystal/pull/15918 [#15947]: https://github.com/crystal-lang/crystal/pull/15947 [#15876]: https://github.com/crystal-lang/crystal/pull/15876 #### tools - Macro code coverage tool ([#15738], thanks @Blacksmoke16) - _(docs-generator)_ Limit paragraph `max-width` in API docs ([#15672], thanks @straight-shoota) [#15738]: https://github.com/crystal-lang/crystal/pull/15738 [#15672]: https://github.com/crystal-lang/crystal/pull/15672 ### Bugfixes #### lang - **[experimental]** Do not use private linkage for slice literal buffers ([#15746], thanks @HertzDevil) [#15746]: https://github.com/crystal-lang/crystal/pull/15746 #### stdlib - Require `NO_COLOR` to be non-empty ([#15880], thanks @HertzDevil) - _(benchmark)_ Use `UInt64` to track iteration count during warm-up calculation in `Benchmark::IPS` ([#15780], thanks @syeopite) - _(collection)_ Fix `Array#|` for different item types ([#15756], thanks @straight-shoota) - _(concurrency)_ Fix calling `Fiber::ExecutionContext#enqueue` from bare `Thread` ([#15767], thanks @ysbaddaden) - _(concurrency)_ Simplify `Crystal::System::Fiber::RESERVED_STACK_SIZE` initializer on Windows ([#15820], thanks @HertzDevil) - _(concurrency)_ Do not print adjacent nodes in `Thread::LinkedList#inspect` ([#15829], thanks @HertzDevil) - _(files)_ Fix async append to file in IOCP ([#15681], thanks @ysbaddaden) - _(numeric)_ **[regression]** Fix `BigFloat#format` not compiling ([#15796], thanks @HertzDevil) - _(numeric)_ Never output exponent in `BigDecimal#format` ([#15795], thanks @HertzDevil) - _(numeric)_ Preserve precision when passing `BigDecimal` or `BigFloat` to `sprintf` `%i` ([#15808], thanks @HertzDevil) - _(numeric)_ Fix `Float32#abs` for signed zeros ([#15814], thanks @HertzDevil) - _(numeric)_ Ensure unary `Float32#-` and `Float64#-` flip sign bit ([#15857], thanks @HertzDevil) - _(runtime)_ reopen async `File` passed to `Process.exec` and `.run` (win32) ([#15703], thanks @ysbaddaden) - _(runtime)_ raise on manual fiber resume from sleep ([#15744], thanks @ysbaddaden) - _(runtime)_ race condition in `Fiber::ExecutionContext::Isolated#wait` ([#15872], thanks @ysbaddaden) - _(runtime)_ Prevent leaking memory when `exec_recursive`'s block raises ([#15893], thanks @straight-shoota) - _(runtime)_ thread specs must test `Thread`, not `Fiber::ExecutionContext::Isolated` ([#15909], thanks @ysbaddaden) - _(system)_ Fix `Path#relative_to` for non-normalized anchor ([#15737], thanks @straight-shoota) - _(system)_ **[regression]** Skip `src/termios.cr` on Windows ([#15852], thanks @HertzDevil) - _(system)_ Suspend Windows processes until job objects are set up ([#15850], thanks @HertzDevil) - _(time)_ Fix `Time::Location::InvalidTZDataError` dropping default message ([#15824], thanks @HertzDevil) - _(time)_ Fix IANA time zone names for Windows system time zones ([#15914], thanks @HertzDevil) [#15880]: https://github.com/crystal-lang/crystal/pull/15880 [#15780]: https://github.com/crystal-lang/crystal/pull/15780 [#15756]: https://github.com/crystal-lang/crystal/pull/15756 [#15767]: https://github.com/crystal-lang/crystal/pull/15767 [#15820]: https://github.com/crystal-lang/crystal/pull/15820 [#15829]: https://github.com/crystal-lang/crystal/pull/15829 [#15681]: https://github.com/crystal-lang/crystal/pull/15681 [#15796]: https://github.com/crystal-lang/crystal/pull/15796 [#15795]: https://github.com/crystal-lang/crystal/pull/15795 [#15808]: https://github.com/crystal-lang/crystal/pull/15808 [#15814]: https://github.com/crystal-lang/crystal/pull/15814 [#15857]: https://github.com/crystal-lang/crystal/pull/15857 [#15703]: https://github.com/crystal-lang/crystal/pull/15703 [#15744]: https://github.com/crystal-lang/crystal/pull/15744 [#15872]: https://github.com/crystal-lang/crystal/pull/15872 [#15893]: https://github.com/crystal-lang/crystal/pull/15893 [#15909]: https://github.com/crystal-lang/crystal/pull/15909 [#15737]: https://github.com/crystal-lang/crystal/pull/15737 [#15852]: https://github.com/crystal-lang/crystal/pull/15852 [#15850]: https://github.com/crystal-lang/crystal/pull/15850 [#15824]: https://github.com/crystal-lang/crystal/pull/15824 [#15914]: https://github.com/crystal-lang/crystal/pull/15914 #### compiler - _(codegen)_ Add file name to file-private virtual types during codegen ([#15897], thanks @HertzDevil) - _(codegen)_ Clear debug location of top-level implicit return ([#15972], thanks @HertzDevil) - _(codegen)_ Add file name to file-private generic instance metaclass types during codegen ([#15974], thanks @HertzDevil) - _(codegen)_ Add debug locations to metaclass nodes and `typeof` ([#15971], thanks @HertzDevil) - _(interpreter)_ Fix interpreter guard clauses for signal handling ([#15892], thanks @straight-shoota) - _(parser)_ Add end locations for `Case`, `Asm`, and `Select` ([#15452], thanks @FnControlOption) - _(parser)_ **[regression]** Fix stringification of `Not` as call receiver ([#15801], thanks @Blacksmoke16) - _(semantic)_ Fix cleanup of one-to-many assignment with untyped RHS ([#15755], thanks @HertzDevil) - _(semantic)_ Do not consider type in `Crystal::Var#==` ([#15884], thanks @HertzDevil) [#15897]: https://github.com/crystal-lang/crystal/pull/15897 [#15972]: https://github.com/crystal-lang/crystal/pull/15972 [#15974]: https://github.com/crystal-lang/crystal/pull/15974 [#15971]: https://github.com/crystal-lang/crystal/pull/15971 [#15892]: https://github.com/crystal-lang/crystal/pull/15892 [#15452]: https://github.com/crystal-lang/crystal/pull/15452 [#15801]: https://github.com/crystal-lang/crystal/pull/15801 [#15755]: https://github.com/crystal-lang/crystal/pull/15755 [#15884]: https://github.com/crystal-lang/crystal/pull/15884 #### tools - _(docs-generator)_ Handle doc locations when file is in parent directory ([#15898], thanks @Blacksmoke16) - _(macro-code-coverage)_ Better handle coverage reporting of `MacroIf` nodes with _only_ `MacroLiteral` bodies ([#15938], thanks @Blacksmoke16) [#15898]: https://github.com/crystal-lang/crystal/pull/15898 [#15938]: https://github.com/crystal-lang/crystal/pull/15938 ### Chores #### stdlib - **[breaking]** Make `Enum.from_value` raise `ArgumentError` instead of `Exception` ([#15624], thanks @HertzDevil) - Fix duplicate keys in hash literals ([#15843], thanks @straight-shoota) - Remove unused code ([#15845], thanks @straight-shoota) - Remove shadowed method arguments ([#15846], thanks @straight-shoota) - Replace some `not_nil!` calls with bang methods ([#15847], thanks @straight-shoota) - Remove useless condition literal ([#15859], thanks @straight-shoota) - Use `be_nil` and `be_true`/`be_false` everywhere in specs ([#15867], thanks @straight-shoota) - Remove trailing whitespace ([#15869], thanks @straight-shoota) - Add trailing newlines ([#15870], thanks @straight-shoota) - _(collection)_ Replace literal conditions with nilable casts ([#15844], thanks @straight-shoota) - _(time)_ Update Windows zone names ([#15728], thanks @straight-shoota) - _(time)_ Update Windows zone names using local database ([#15837], thanks @HertzDevil) [#15624]: https://github.com/crystal-lang/crystal/pull/15624 [#15843]: https://github.com/crystal-lang/crystal/pull/15843 [#15845]: https://github.com/crystal-lang/crystal/pull/15845 [#15846]: https://github.com/crystal-lang/crystal/pull/15846 [#15847]: https://github.com/crystal-lang/crystal/pull/15847 [#15859]: https://github.com/crystal-lang/crystal/pull/15859 [#15867]: https://github.com/crystal-lang/crystal/pull/15867 [#15869]: https://github.com/crystal-lang/crystal/pull/15869 [#15870]: https://github.com/crystal-lang/crystal/pull/15870 [#15844]: https://github.com/crystal-lang/crystal/pull/15844 [#15728]: https://github.com/crystal-lang/crystal/pull/15728 [#15837]: https://github.com/crystal-lang/crystal/pull/15837 #### compiler - Replace `is_a?` calls with convenient alternatives ([#15860], thanks @straight-shoota) [#15860]: https://github.com/crystal-lang/crystal/pull/15860 #### other - Fix typos and add `typos` integration ([#15873], thanks @straight-shoota) [#15873]: https://github.com/crystal-lang/crystal/pull/15873 ### Performance #### lang - **[experimental]** Optimize slice literal codegen on LLVM 21 ([#15803], thanks @HertzDevil) [#15803]: https://github.com/crystal-lang/crystal/pull/15803 #### stdlib - _(collection)_ Optimize `Indexable#find` ([#15674], thanks @straight-shoota) - _(numeric)_ Add specialized implementations for `Float#infinite?` and `#nan?` ([#15813], thanks @HertzDevil) [#15674]: https://github.com/crystal-lang/crystal/pull/15674 [#15813]: https://github.com/crystal-lang/crystal/pull/15813 #### compiler - Apply performance improvement suggestions from ameba ([#15839], thanks @straight-shoota) - _(codegen)_ Simplify codegen of mixed-type checked integer addition and subtraction ([#15878], thanks @HertzDevil) [#15839]: https://github.com/crystal-lang/crystal/pull/15839 [#15878]: https://github.com/crystal-lang/crystal/pull/15878 ### Refactor #### stdlib - _(collection)_ Make `offset` a required parameter in `Indexable#find` ([#15671], thanks @straight-shoota) - _(crypto)_ Add extra `Digest.update` overloads for `Bytes` ([#15736], thanks @straight-shoota) - _(crypto)_ **[experimental]** Use `Slice` literals in `Crypto::Bcrypt` ([#15781], thanks @HertzDevil) - _(files)_ Ask system to decide non-blocking `IO::FileDescriptor` (win32) ([#15753], thanks @ysbaddaden) - _(files)_ `Crystal::EventLoop::FileDescriptor#open` now sets the non/blocking flag ([#15754], thanks @ysbaddaden) - _(networking)_ Use relative requires for `http/` files ([#15675], thanks @straight-shoota) - _(networking)_ Split `StaticFileHandler#call` into structured components ([#15678], thanks @straight-shoota) - _(numeric)_ **[experimental]** Use `Slice.literal` for `fast_float` when supported ([#15667], thanks @HertzDevil) - _(numeric)_ Combine the decimal number printing implementations ([#15815], thanks @HertzDevil) - _(runtime)_ Extract bindings for LibC errno to `src/lib_c/` ([#15565], thanks @ysbaddaden) - _(runtime)_ Extract `Exception::CallStack.decode_backtrace_frame` helper ([#15615], thanks @ysbaddaden) - _(runtime)_ Let `Crystal::EventLoop#close` do the actual close (not just cleanup) ([#15641], thanks @ysbaddaden) - _(serialization)_ Replace deprecated `LibXML.xmlGcMemSetup` with `.xmlMemSetup` ([#15626], thanks @straight-shoota) - _(serialization)_ XML: modernize API when available & workaround issues with legacy versions ([#15899], thanks @ysbaddaden) - _(specs)_ Support arbitrary `IO`s in `Spec::CLI` ([#15882], thanks @HertzDevil) - _(specs)_ Replace some lookup hashes in `Spec` with exhaustive cases ([#15879], thanks @HertzDevil) - _(text)_ **[experimental]** Use slice literals for `String::CHAR_TO_DIGIT` and `CHAR_TO_DIGIT62` ([#15745], thanks @HertzDevil) - _(text)_ Replace some uses of `String#%` with justification methods ([#15821], thanks @HertzDevil) - _(text)_ Avoid calling `chars.size` on `String`s ([#15822], thanks @HertzDevil) - _(time)_ Move most POSIX TZ string functionality to a module ([#15866], thanks @HertzDevil) [#15671]: https://github.com/crystal-lang/crystal/pull/15671 [#15736]: https://github.com/crystal-lang/crystal/pull/15736 [#15781]: https://github.com/crystal-lang/crystal/pull/15781 [#15753]: https://github.com/crystal-lang/crystal/pull/15753 [#15754]: https://github.com/crystal-lang/crystal/pull/15754 [#15675]: https://github.com/crystal-lang/crystal/pull/15675 [#15678]: https://github.com/crystal-lang/crystal/pull/15678 [#15667]: https://github.com/crystal-lang/crystal/pull/15667 [#15815]: https://github.com/crystal-lang/crystal/pull/15815 [#15565]: https://github.com/crystal-lang/crystal/pull/15565 [#15615]: https://github.com/crystal-lang/crystal/pull/15615 [#15641]: https://github.com/crystal-lang/crystal/pull/15641 [#15626]: https://github.com/crystal-lang/crystal/pull/15626 [#15899]: https://github.com/crystal-lang/crystal/pull/15899 [#15882]: https://github.com/crystal-lang/crystal/pull/15882 [#15879]: https://github.com/crystal-lang/crystal/pull/15879 [#15745]: https://github.com/crystal-lang/crystal/pull/15745 [#15821]: https://github.com/crystal-lang/crystal/pull/15821 [#15822]: https://github.com/crystal-lang/crystal/pull/15822 [#15866]: https://github.com/crystal-lang/crystal/pull/15866 #### compiler - _(codegen)_ Replace type-id function with lookup table ([#15904], thanks @BlobCodes) [#15904]: https://github.com/crystal-lang/crystal/pull/15904 ### Documentation #### stdlib - _(crypto)_ Add type restrictions to `Digest` ([#15696], thanks @Vici37) - _(crypto)_ Add documentation for `Crypto::Bcrypt::Password#to_s` ([#15935], thanks @hugopl) - _(crypto)_ Improve docs for `OpenSSL::Cipher` ([#15964], thanks @Fijxu) - _(macros)_ **[experimental]** Document `Crystal::Macros::StringLiteral#to_utf16` ([#15748], thanks @HertzDevil) - _(runtime)_ Document `GC::Stats` properties ([#15676], thanks @ysbaddaden) - _(runtime)_ Add links to language specification in docs for pseudo methods ([#15864], thanks @straight-shoota) - _(runtime)_ Fix unclosed codeblock in `__crystal_pseudo_alignof` docs ([#15945], thanks @syeopite) - _(serialization)_ Add type restrictions to `CSV` ([#15695], thanks @Vici37) - _(specs)_ Clarify docs in regards to what `be_nil` expectation does ([#15954], thanks @Blacksmoke16) - _(system)_ Add type restrictions to `Dir` ([#15697], thanks @Vici37) - _(system)_ Improve docs for `Socket` and `IO::FileDescriptor` handles ([#15977], thanks @straight-shoota) - _(text)_ Improve docs for `String#lines` and `#each_line` ([#15894], thanks @straight-shoota) [#15696]: https://github.com/crystal-lang/crystal/pull/15696 [#15935]: https://github.com/crystal-lang/crystal/pull/15935 [#15964]: https://github.com/crystal-lang/crystal/pull/15964 [#15748]: https://github.com/crystal-lang/crystal/pull/15748 [#15676]: https://github.com/crystal-lang/crystal/pull/15676 [#15864]: https://github.com/crystal-lang/crystal/pull/15864 [#15945]: https://github.com/crystal-lang/crystal/pull/15945 [#15695]: https://github.com/crystal-lang/crystal/pull/15695 [#15954]: https://github.com/crystal-lang/crystal/pull/15954 [#15697]: https://github.com/crystal-lang/crystal/pull/15697 [#15977]: https://github.com/crystal-lang/crystal/pull/15977 [#15894]: https://github.com/crystal-lang/crystal/pull/15894 #### compiler - _(parser)_ Improve examples for the syntax highlighter documentation ([#15699], thanks @tamdaz) [#15699]: https://github.com/crystal-lang/crystal/pull/15699 ### Specs #### stdlib - Drop `to_a` in expectations with `Slice` ([#15735], thanks @straight-shoota) - _(crypto)_ Unroll test data in specs for `crypto/subtle` ([#15702], thanks @straight-shoota) - _(networking)_ Add test for `HTTP::Request` with resource string `//` ([#15546], thanks @miry) - _(networking)_ Pick TCP and UDP local ports differently in socket specs ([#15828], thanks @HertzDevil) - _(serialization)_ Remove forgotten debug `puts` call ([#15942], thanks @Sija) - _(text)_ Simplify specs for string comparison ([#15868], thanks @straight-shoota) [#15735]: https://github.com/crystal-lang/crystal/pull/15735 [#15702]: https://github.com/crystal-lang/crystal/pull/15702 [#15546]: https://github.com/crystal-lang/crystal/pull/15546 [#15828]: https://github.com/crystal-lang/crystal/pull/15828 [#15942]: https://github.com/crystal-lang/crystal/pull/15942 [#15868]: https://github.com/crystal-lang/crystal/pull/15868 #### compiler - _(interpreter)_ Enable interpreter integration test for XML ([#15628], thanks @straight-shoota) - _(parser)_ Cleanup parser specs ([#15446], thanks @FnControlOption) [#15628]: https://github.com/crystal-lang/crystal/pull/15628 [#15446]: https://github.com/crystal-lang/crystal/pull/15446 #### tools - _(formatter)_ Fix formatter specs with string interpolation ([#15842], thanks @straight-shoota) [#15842]: https://github.com/crystal-lang/crystal/pull/15842 ### Infrastructure - Changelog for 1.17.0 ([#15900], [#15983], thanks @straight-shoota) - Update previous Crystal release 1.16.1 ([#15649], thanks @straight-shoota) - Update `release-update` script: Truncate CHANGELOG ([#15679], thanks @straight-shoota) - Merge `release/1.16` into master ([#15729], thanks @straight-shoota) - Simplify `docs_main.cr` ([#15621], thanks @straight-shoota) - Update previous Crystal release 1.16.2 ([#15730], thanks @straight-shoota) - Fix order of title clean steps in github-changelog helper ([#15727], thanks @straight-shoota) - Fix `scripts/release-update.sh` idempotent previous CHANGELOG entry ([#15731], thanks @straight-shoota) - Merge `release/1.16`@1.16.3 into master ([#15774], thanks @straight-shoota) - Update previous Crystal release 1.16.3 ([#15773], thanks @straight-shoota) - Makefile: Fix target location for `install_docs` ([#15853], thanks @straight-shoota) - Add ameba ([#15875], thanks @straight-shoota) - Allow-list Crystal's funding.json from the project ([#15969], thanks @matiasgarciaisaia) - Allow `LLVM_VERSION` override inside `Makefile` ([#15765], thanks @HertzDevil) - Add build script for `spec/std/data/zoneinfo.zip` ([#15831], thanks @HertzDevil) - _(ci)_ Update GH Actions ([#15668], thanks @renovate) - _(ci)_ Add `XML CI` workflow ([#15923], thanks @straight-shoota) - _(ci)_ Update typos 1.34.0 ([#15950], thanks @straight-shoota) - _(ci)_ Update korthout/backport-action action to v3.2.1 ([#15949], thanks @renovate) - _(ci)_ Update cygwin/cygwin-install-action action to v6 ([#15965], thanks @renovate) - _(ci)_ Drop the static LLVM libraries on Windows MSVC CI ([#15797], thanks @HertzDevil) - _(ci)_ Set up Inno Setup explicitly on MSVC CI ([#15851], [#15861], thanks @HertzDevil) - _(ci)_ Update library versions for MSVC CI ([#15921], thanks @HertzDevil) - _(ci)_ Add CI workflow for MinGW-w64 ARM64 builds ([#15794], thanks @HertzDevil) - _(ci)_ **[regression]** Use `CMAKE_MSVC_RUNTIME_LIBRARY` for the MSVC PCRE2 static library ([#15802], thanks @HertzDevil) [#15900]: https://github.com/crystal-lang/crystal/pull/15900 [#15983]: https://github.com/crystal-lang/crystal/pull/15983 [#15649]: https://github.com/crystal-lang/crystal/pull/15649 [#15679]: https://github.com/crystal-lang/crystal/pull/15679 [#15729]: https://github.com/crystal-lang/crystal/pull/15729 [#15621]: https://github.com/crystal-lang/crystal/pull/15621 [#15730]: https://github.com/crystal-lang/crystal/pull/15730 [#15727]: https://github.com/crystal-lang/crystal/pull/15727 [#15731]: https://github.com/crystal-lang/crystal/pull/15731 [#15774]: https://github.com/crystal-lang/crystal/pull/15774 [#15773]: https://github.com/crystal-lang/crystal/pull/15773 [#15853]: https://github.com/crystal-lang/crystal/pull/15853 [#15875]: https://github.com/crystal-lang/crystal/pull/15875 [#15969]: https://github.com/crystal-lang/crystal/pull/15969 [#15765]: https://github.com/crystal-lang/crystal/pull/15765 [#15831]: https://github.com/crystal-lang/crystal/pull/15831 [#15668]: https://github.com/crystal-lang/crystal/pull/15668 [#15923]: https://github.com/crystal-lang/crystal/pull/15923 [#15950]: https://github.com/crystal-lang/crystal/pull/15950 [#15949]: https://github.com/crystal-lang/crystal/pull/15949 [#15965]: https://github.com/crystal-lang/crystal/pull/15965 [#15797]: https://github.com/crystal-lang/crystal/pull/15797 [#15851]: https://github.com/crystal-lang/crystal/pull/15851 [#15861]: https://github.com/crystal-lang/crystal/pull/15861 [#15921]: https://github.com/crystal-lang/crystal/pull/15921 [#15794]: https://github.com/crystal-lang/crystal/pull/15794 [#15802]: https://github.com/crystal-lang/crystal/pull/15802 ================================================ FILE: doc/changelogs/v1.18.md ================================================ # Changelog 1.18 ## [1.18.2] (2025-10-21) [1.18.2]: https://github.com/crystal-lang/crystal/releases/1.18.2 ### Bugfixes #### stdlib - _(files)_ **[regression]** Revert type restriction for `IO#read_bytes` ([#16231], thanks @straight-shoota) - _(runtime)_ Fix `Fiber::ExecutionContext.default_workers_count` to avoid taking into account unsupported values ([#16227], thanks @Sija) [#16231]: https://github.com/crystal-lang/crystal/pull/16231 [#16227]: https://github.com/crystal-lang/crystal/pull/16227 ### Infrastructure - Changelog for 1.18.2 ([#16243], thanks @matiasgarciaisaia) [#16243]: https://github.com/crystal-lang/crystal/pull/16243 ## [1.18.1] (2025-10-17) [1.18.1]: https://github.com/crystal-lang/crystal/releases/1.18.1 ### Bugfixes #### stdlib - _(networking)_ **[regression]** Revert adding type restrictions on `HTTP::WebSocket#send` etc. ([#16218], thanks @straight-shoota) [#16218]: https://github.com/crystal-lang/crystal/pull/16218 #### compiler - _(parser)_ **[regression]** Fix allow space after base type in enum def ([#16217], thanks @straight-shoota) [#16217]: https://github.com/crystal-lang/crystal/pull/16217 ### Infrastructure - Changelog for 1.18.1 ([#16224], thanks @matiasgarciaisaia) [#16224]: https://github.com/crystal-lang/crystal/pull/16224 ## [1.18.0] (2025-10-14) [1.18.0]: https://github.com/crystal-lang/crystal/releases/1.18.0 ### Features #### lang - Support `ProcPointer`s of lib funs with parameter types ([#16089], thanks @HertzDevil) - _(annotations)_ Print deprecation warning on types and aliases ([#15962], thanks @ysbaddaden) - _(annotations)_ Print deprecation warnings on deprecated method argument ([#15999], thanks @ysbaddaden) - _(macros)_ **[breaking]** Expand empty `(Named)TupleLiteral` to `(Named)Tuple.new` instead of `{}` ([#16108], thanks @spuun) - _(macros)_ Add `ArrayLiteral#*`, `StringLiteral#*` and `TupleLiteral#*` ([#16154], [#16206], thanks @jneen, @ysbaddaden) [#16089]: https://github.com/crystal-lang/crystal/pull/16089 [#15962]: https://github.com/crystal-lang/crystal/pull/15962 [#15999]: https://github.com/crystal-lang/crystal/pull/15999 [#16108]: https://github.com/crystal-lang/crystal/pull/16108 [#16154]: https://github.com/crystal-lang/crystal/pull/16154 [#16206]: https://github.com/crystal-lang/crystal/pull/16206 #### stdlib - Add `summary_width` and `summary_indent` to `OptionParser` ([#15326], thanks @kojix2) - _(collection)_ Add `Set#select!` and `#reject!` ([#16060], thanks @HertzDevil) - _(concurrency)_ Speed up `Parallel::Scheduler#quick_dequeue?` for `max=1` ([#15961], thanks @ysbaddaden) - _(concurrency)_ Default execution context is now parallel (MT:1) ([#16136], thanks @ysbaddaden) - _(files)_ **[deprecation]** Add `.set_blocking` to `Socket` and `IO::FileDescriptor` and deprecate `#blocking` property ([#16033], [#16129], thanks @ysbaddaden) - _(llvm)_ Support LLVM 21.1 and 22.0 ([#16062], [#16198], thanks @HertzDevil, @straight-shoota) - _(macros)_ Add `NumberLiteral#zero?` ([#10248], thanks @Sija) - _(macros)_ Add `thread_local` macro ([#16173], thanks @ysbaddaden) - _(networking)_ Fix `URI#host=` to wrap IPv6 address in brackets ([#16164], thanks @stakach) - _(runtime)_ Lazily instantiate the event loop of isolated execution contexts ([#16063], thanks @ysbaddaden) - _(runtime)_ Add `Fiber::ExecutionContext::Parallel#resize` ([#15956], thanks @ysbaddaden) - _(runtime)_ Add `Crystal::System.effective_cpu_count` ([#16148], thanks @ysbaddaden) - _(runtime)_ Improve `Fiber::ExecutionContext.default_workers_count` ([#16149], thanks @ysbaddaden) - _(serialization)_ Add `Time::Location.from_json_object_key` ([#15957], thanks @Sija) - _(serialization)_ Resolve YAML aliases in `YAML::Any` ([#15941], thanks @willhbr) - _(serialization)_ Embed libxml2 version number on Windows MSVC ([#16104], thanks @HertzDevil) - _(serialization)_ Add `JSON::Any` wrapper around `JSON::Any#inspect` output ([#15979], thanks @jneen) - _(specs)_ Add `with_tempdir` spec helper ([#16005], thanks @straight-shoota) - _(system)_ Add `File.readlink?` ([#16004], thanks @straight-shoota) - _(text)_ Add `SemanticVersion.valid?` & `SemanticVersion.parse?` ([#15051], thanks @devnote-dev) - _(text)_ Add `String.additive_identity` ([#15998], thanks @straight-shoota) - _(text)_ Use proper ANSI reset codes in `Colorize` ([#16052], thanks @Blacksmoke16) - _(text)_ Update Unicode to 17.0.0 ([#16160], thanks @HertzDevil) - _(time)_ Use canonical IANA name for the local Windows system time zone ([#15967], thanks @HertzDevil) - _(time)_ Load `Location.local` by symlink name ([#16002], [#16022], thanks @straight-shoota) - _(time)_ Add `Time::Location.load?` ([#16121], thanks @straight-shoota) - _(time)_ Format `Time#inspect` with Internet Extended Date/Time Format ([#16039], thanks @straight-shoota) [#15326]: https://github.com/crystal-lang/crystal/pull/15326 [#16060]: https://github.com/crystal-lang/crystal/pull/16060 [#15961]: https://github.com/crystal-lang/crystal/pull/15961 [#16136]: https://github.com/crystal-lang/crystal/pull/16136 [#16033]: https://github.com/crystal-lang/crystal/pull/16033 [#16129]: https://github.com/crystal-lang/crystal/pull/16129 [#16062]: https://github.com/crystal-lang/crystal/pull/16062 [#16198]: https://github.com/crystal-lang/crystal/pull/16198 [#10248]: https://github.com/crystal-lang/crystal/pull/10248 [#16173]: https://github.com/crystal-lang/crystal/pull/16173 [#16164]: https://github.com/crystal-lang/crystal/pull/16164 [#16063]: https://github.com/crystal-lang/crystal/pull/16063 [#15956]: https://github.com/crystal-lang/crystal/pull/15956 [#16148]: https://github.com/crystal-lang/crystal/pull/16148 [#16149]: https://github.com/crystal-lang/crystal/pull/16149 [#15957]: https://github.com/crystal-lang/crystal/pull/15957 [#15941]: https://github.com/crystal-lang/crystal/pull/15941 [#16104]: https://github.com/crystal-lang/crystal/pull/16104 [#15979]: https://github.com/crystal-lang/crystal/pull/15979 [#16005]: https://github.com/crystal-lang/crystal/pull/16005 [#16004]: https://github.com/crystal-lang/crystal/pull/16004 [#15051]: https://github.com/crystal-lang/crystal/pull/15051 [#15998]: https://github.com/crystal-lang/crystal/pull/15998 [#16052]: https://github.com/crystal-lang/crystal/pull/16052 [#16160]: https://github.com/crystal-lang/crystal/pull/16160 [#15967]: https://github.com/crystal-lang/crystal/pull/15967 [#16002]: https://github.com/crystal-lang/crystal/pull/16002 [#16022]: https://github.com/crystal-lang/crystal/pull/16022 [#16121]: https://github.com/crystal-lang/crystal/pull/16121 [#16039]: https://github.com/crystal-lang/crystal/pull/16039 #### compiler - _(cli)_ Add the ability to dump type information to a JSON file ([#16027], thanks @HertzDevil) - _(interpreter)_ Support `Proc.new(Void*, Void*)` in the interpreter ([#16044], thanks @HertzDevil) - _(interpreter:repl)_ Fully exit the process on `exit!` from REPL ([#16171], thanks @jneen) - _(semantic)_ Resolve types when guessing return type from class method overloads ([#16118], thanks @HertzDevil) - _(semantic)_ Guess instance variable types from global method calls ([#16119], thanks @HertzDevil) [#16027]: https://github.com/crystal-lang/crystal/pull/16027 [#16044]: https://github.com/crystal-lang/crystal/pull/16044 [#16171]: https://github.com/crystal-lang/crystal/pull/16171 [#16118]: https://github.com/crystal-lang/crystal/pull/16118 [#16119]: https://github.com/crystal-lang/crystal/pull/16119 #### tools - _(docs-generator)_ Add support for deprecated parameters in doc generator ([#16012], thanks @straight-shoota) - _(hierarchy)_ Show extern union types in hierarchy tool ([#16026], thanks @HertzDevil) [#16012]: https://github.com/crystal-lang/crystal/pull/16012 [#16026]: https://github.com/crystal-lang/crystal/pull/16026 ### Bugfixes #### stdlib - _(files)_ Fix `fcntl` reference for `fds[1]` in socketpair setup ([#16072], thanks @kojix2) - _(log)_ Make crystal log resilient to empty LOG_LEVEL env var ([#15963], thanks @anaPerezGhiglia) - _(networking)_ Preserve query params in `StaticFileHandler` redirects ([#15789], thanks @syeopite) - _(networking)_ Fix `StaticFileHandler` to return 404 on file error ([#16025], [#16077], thanks @straight-shoota) - _(networking)_ Run `before_request` callback in `HTTP::Client` only once ([#16064], thanks @straight-shoota) - _(networking)_ Fix `HTTP::Request#query=` typing ([#16143], thanks @Blacksmoke16) - _(runtime)_ `Fiber::ExecutionContext::Parallel::Scheduler#tick` must be unsigned ([#16155], thanks @ysbaddaden) - _(serialization)_ Fix add missing `#==` overloads for `Log::Metadata::Value` and `YAML::Any` ([#15732], thanks @straight-shoota) - _(serialization)_ Fix pointer access bug in `XML::NodeSet` ([#16055], thanks @toddsundsted) - _(serialization)_ Remove `NOERROR` from LibXML default options ([#16103], thanks @straight-shoota) - _(serialization)_ Move `*::Serializable`'s private constructors into `macro included` hook ([#16147], thanks @HertzDevil) - _(serialization)_ Correctly reference global JSON/YAML modules ([#16161], [#16169], thanks @Sija, @straight-shoota) - _(serialization)_ Fix element type inference in `YAML::ArrayConverter.from_yaml` ([#16166], thanks @HertzDevil) - _(system)_ Fix return type of `system_close_on_exec=` on Windows ([#16095], thanks @straight-shoota) - _(time)_ Fix time zone identifier `America/Argentina/Buenos_Aires` ([#16078], thanks @straight-shoota) - _(time)_ Fix `Time#at_beginning_of_week`,`#at_end_of_week` to respect local timezone ([#16113], thanks @straight-shoota) [#16072]: https://github.com/crystal-lang/crystal/pull/16072 [#15963]: https://github.com/crystal-lang/crystal/pull/15963 [#15789]: https://github.com/crystal-lang/crystal/pull/15789 [#16025]: https://github.com/crystal-lang/crystal/pull/16025 [#16077]: https://github.com/crystal-lang/crystal/pull/16077 [#16064]: https://github.com/crystal-lang/crystal/pull/16064 [#16143]: https://github.com/crystal-lang/crystal/pull/16143 [#16155]: https://github.com/crystal-lang/crystal/pull/16155 [#15732]: https://github.com/crystal-lang/crystal/pull/15732 [#16055]: https://github.com/crystal-lang/crystal/pull/16055 [#16103]: https://github.com/crystal-lang/crystal/pull/16103 [#16147]: https://github.com/crystal-lang/crystal/pull/16147 [#16161]: https://github.com/crystal-lang/crystal/pull/16161 [#16169]: https://github.com/crystal-lang/crystal/pull/16169 [#16166]: https://github.com/crystal-lang/crystal/pull/16166 [#16095]: https://github.com/crystal-lang/crystal/pull/16095 [#16078]: https://github.com/crystal-lang/crystal/pull/16078 [#16113]: https://github.com/crystal-lang/crystal/pull/16113 #### compiler - _(codegen)_ Never generate assignments to a block's underscore parameters ([#16057], thanks @HertzDevil) - _(codegen)_ Fix `@[Primitive]` codegen for typedefs ([#16110], thanks @HertzDevil) - _(interpreter)_ never generate assignments to a block's underscore parameters ([#16058], thanks @HertzDevil) - _(interpreter)_ Add `writer.close_on_finalize = false` for signal pipe ([#16167], thanks @straight-shoota) - _(interpreter:repl)_ Continue REPL prompt if input consists entirely of annotations ([#16045], thanks @HertzDevil) - _(parser)_ Disallow unterminated escaped heredoc without trailing newline ([#16046], thanks @HertzDevil) - _(parser)_ Require space, semicolon, or newline after class/module/etc. header ([#13375], thanks @FnControlOption) - _(parser)_ Fix parsing `ReadInstanceVar` in short block syntax ([#16099], thanks @nobodywasishere) - _(semantic)_ Pass through variable types unchanged in a while loop ([#15980], thanks @HertzDevil) - _(semantic)_ deprecation warning for (expanded) deprecated def ([#15997], thanks @ysbaddaden) - _(semantic)_ Copy annotations in `Crystal::Arg#copy_without_location` ([#16008], thanks @ysbaddaden) - _(semantic)_ Copy annotations in `Crystal::Def#expand_default_arguments` ([#16007], thanks @ysbaddaden) - _(semantic)_ Copy annotations in `Crystal::Def#expand_new_default_arguments` ([#16013], thanks @ysbaddaden) - _(semantic)_ Fix error message for `StaticArray` with non-integer generic argument `N` ([#16037], thanks @straight-shoota) - _(semantic)_ Resolve bound type parameters from generic superclass during path lookup ([#10839], thanks @HertzDevil) - _(semantic)_ **[regression]** Ensure hash literals are evaluated from left to right ([#16124], thanks @HertzDevil) [#16057]: https://github.com/crystal-lang/crystal/pull/16057 [#16110]: https://github.com/crystal-lang/crystal/pull/16110 [#16058]: https://github.com/crystal-lang/crystal/pull/16058 [#16167]: https://github.com/crystal-lang/crystal/pull/16167 [#16045]: https://github.com/crystal-lang/crystal/pull/16045 [#16046]: https://github.com/crystal-lang/crystal/pull/16046 [#13375]: https://github.com/crystal-lang/crystal/pull/13375 [#16099]: https://github.com/crystal-lang/crystal/pull/16099 [#15980]: https://github.com/crystal-lang/crystal/pull/15980 [#15997]: https://github.com/crystal-lang/crystal/pull/15997 [#16008]: https://github.com/crystal-lang/crystal/pull/16008 [#16007]: https://github.com/crystal-lang/crystal/pull/16007 [#16013]: https://github.com/crystal-lang/crystal/pull/16013 [#16037]: https://github.com/crystal-lang/crystal/pull/16037 [#10839]: https://github.com/crystal-lang/crystal/pull/10839 [#16124]: https://github.com/crystal-lang/crystal/pull/16124 ### Chores #### stdlib - Drop `Thread::Local(T)` ([#16179], thanks @ysbaddaden) - _(concurrency)_ **[deprecation]** Deprecate `Atomic::Flag` ([#15805], thanks @ysbaddaden) - _(files)_ **[deprecation]** Deprecate the `blocking` parameter of `File`, `Socket` and `IO::FileDescriptor` constructors ([#16034], [#16043], [#16047], thanks @ysbaddaden, @Blacksmoke16) - _(numeric)_ **[deprecation]** Deprecate `Float::Printer::IEEE` ([#16050], thanks @HertzDevil) - _(system)_ **[deprecation]** Deprecate `Process::Status#exit_signal` ([#16003], thanks @straight-shoota) [#16179]: https://github.com/crystal-lang/crystal/pull/16179 [#15805]: https://github.com/crystal-lang/crystal/pull/15805 [#16034]: https://github.com/crystal-lang/crystal/pull/16034 [#16043]: https://github.com/crystal-lang/crystal/pull/16043 [#16047]: https://github.com/crystal-lang/crystal/pull/16047 [#16050]: https://github.com/crystal-lang/crystal/pull/16050 [#16003]: https://github.com/crystal-lang/crystal/pull/16003 ### Performance #### lang - Optimize `Enum.parse?`, avoiding allocations ([#15927], [#16192], thanks @jgaskins, @straight-shoota) [#15927]: https://github.com/crystal-lang/crystal/pull/15927 [#16192]: https://github.com/crystal-lang/crystal/pull/16192 #### stdlib - _(numeric)_ Do not use equality checks in `Int#upto` and `#downto` ([#16076], thanks @HertzDevil) - _(system)_ Simplify buffer for `File.readlink` ([#16021], thanks @straight-shoota) - _(time)_ Optimize `Time#to_s` ([#16042], thanks @straight-shoota) [#16076]: https://github.com/crystal-lang/crystal/pull/16076 [#16021]: https://github.com/crystal-lang/crystal/pull/16021 [#16042]: https://github.com/crystal-lang/crystal/pull/16042 #### compiler - Inline `Crystal.check_type_can_be_stored` ([#16130], thanks @HertzDevil) - _(codegen)_ Group temporary variables by file name: compound array assignments ([#16122], thanks @HertzDevil) [#16130]: https://github.com/crystal-lang/crystal/pull/16130 [#16122]: https://github.com/crystal-lang/crystal/pull/16122 ### Refactor #### stdlib - _(concurrency)_ Refactor redundant `begin ... end` blocks ([#16011], thanks @straight-shoota) - _(networking)_ Reorder implementation of `HTTP::Cookies#<<` and `[]=` ([#16107], thanks @straight-shoota) - _(runtime)_ Remove nilable pointers in `Crystal::PointerPairingHeap` ([#15973], thanks @HertzDevil) - _(runtime)_ Remove nilable pointer in `Crystal::EventLoop::IOCP#@timer_packet` ([#15975], thanks @HertzDevil) - _(runtime)_ Remove minimum in `Fiber::ExecutionContext::Parallel` ([#15946], thanks @ysbaddaden) - _(runtime)_ Pass `fd` implicitly to `System::FileDescriptor` and `System::Socket` ([#16137], [#16183], thanks @ysbaddaden) - _(runtime)_ Drop custom implementation of `Fiber::ExecutionContext::Concurrent` ([#16135], thanks @ysbaddaden) - _(specs)_ Keep own colorization state in `Spec::CLI` ([#15926], thanks @HertzDevil) - _(text)_ Use `ensure_suffix` instead of manually checking for suffixes ([#15858], thanks @MatheusRich) - _(time)_ Remove the old Windows time zone name table ([#16006], thanks @HertzDevil) [#16011]: https://github.com/crystal-lang/crystal/pull/16011 [#16107]: https://github.com/crystal-lang/crystal/pull/16107 [#15973]: https://github.com/crystal-lang/crystal/pull/15973 [#15975]: https://github.com/crystal-lang/crystal/pull/15975 [#15946]: https://github.com/crystal-lang/crystal/pull/15946 [#16137]: https://github.com/crystal-lang/crystal/pull/16137 [#16183]: https://github.com/crystal-lang/crystal/pull/16183 [#16135]: https://github.com/crystal-lang/crystal/pull/16135 [#15926]: https://github.com/crystal-lang/crystal/pull/15926 [#15858]: https://github.com/crystal-lang/crystal/pull/15858 [#16006]: https://github.com/crystal-lang/crystal/pull/16006 #### compiler - _(codegen)_ Refactor `Compiler#must_compile?` to clarify the rules. ([#16056], thanks @kojix2) - _(parser)_ Add `#has_any_args?` method for `ASTNode`s ([#16115], thanks @straight-shoota) [#16056]: https://github.com/crystal-lang/crystal/pull/16056 [#16115]: https://github.com/crystal-lang/crystal/pull/16115 #### tools - _(formatter)_ Simplify control flow in formatter for `Call` nodes ([#16170], thanks @straight-shoota) [#16170]: https://github.com/crystal-lang/crystal/pull/16170 #### other - Refactor `unless ... else` ([#16010], thanks @straight-shoota) - Removed unused variables ([#16014], thanks @straight-shoota) [#16010]: https://github.com/crystal-lang/crystal/pull/16010 [#16014]: https://github.com/crystal-lang/crystal/pull/16014 ### Documentation #### lang - _(annotations)_ Enhance documentation of `Deprecated` annotation ([#16195], thanks @straight-shoota) [#16195]: https://github.com/crystal-lang/crystal/pull/16195 #### stdlib - _(benchmark)_ Add type restrictions to benchmark directory ([#15688], thanks @Vici37) - _(concurrency)_ Improve docs for `Channel#close` ([#15910], thanks @anaPerezGhiglia) - _(crypto)_ Fix doc example for `Crypto::BCrypt.new(String, String, Int)` ([#15931], thanks @hugopl) - _(crypto)_ Add type restrictions to crypto directory ([#15694], thanks @Vici37) - _(files)_ Add type restrictions to mime ([#15834], thanks @Vici37) - _(files)_ Fix `IO::TimeoutError` documentation use of deprecated `read_timeout=` ([#16073], thanks @lachlan) - _(files)_ Add type restrictions to io ([#15698], thanks @Vici37) - _(llvm)_ Deprecate each `LLVM::ABI::*` classes ([#15989], thanks @ysbaddaden) - _(log)_ Add type restrictions to Log directory ([#15777], thanks @Vici37) - _(networking)_ Add type restrictions to Oauth directory ([#15687], thanks @Vici37) - _(networking)_ Add type restrictions to http ([#15710], thanks @Vici37) - _(numeric)_ Add type restrictions to big ([#15689], thanks @Vici37) - _(runtime)_ Fix typo in `Object` docs ([#16035], thanks @plambert) - _(runtime)_ Tweak docs for `Fiber::ExecutionContext` ([#16196], thanks @ysbaddaden) - _(serialization)_ Add type restrictions to json ([#15840], [#16142], thanks @Vici37, @Sija) - _(serialization)_ Add note about default constructor in `*::Serializable` ([#16080], thanks @HertzDevil) - _(system)_ Add type restrictions to `args` parameter in `Process` ([#16031], thanks @BigBoyBarney) - _(system)_ Add missing `File::NotFoundError` exception documentation for `File.open` ([#15826], thanks @Fijxu) - _(text)_ Fix return type definition of `String#match_full!` method ([#16001], thanks @Sija) - _(time)_ Update links to ISO-8601 to point to an archived version of the page ([#15985], thanks @nobodywasishere) - _(time)_ Improve docs for `Time#to_local_in` ([#16041], thanks @straight-shoota) [#15688]: https://github.com/crystal-lang/crystal/pull/15688 [#15910]: https://github.com/crystal-lang/crystal/pull/15910 [#15931]: https://github.com/crystal-lang/crystal/pull/15931 [#15694]: https://github.com/crystal-lang/crystal/pull/15694 [#15834]: https://github.com/crystal-lang/crystal/pull/15834 [#16073]: https://github.com/crystal-lang/crystal/pull/16073 [#15698]: https://github.com/crystal-lang/crystal/pull/15698 [#15989]: https://github.com/crystal-lang/crystal/pull/15989 [#15777]: https://github.com/crystal-lang/crystal/pull/15777 [#15687]: https://github.com/crystal-lang/crystal/pull/15687 [#15710]: https://github.com/crystal-lang/crystal/pull/15710 [#15689]: https://github.com/crystal-lang/crystal/pull/15689 [#16035]: https://github.com/crystal-lang/crystal/pull/16035 [#16196]: https://github.com/crystal-lang/crystal/pull/16196 [#15840]: https://github.com/crystal-lang/crystal/pull/15840 [#16142]: https://github.com/crystal-lang/crystal/pull/16142 [#16080]: https://github.com/crystal-lang/crystal/pull/16080 [#16031]: https://github.com/crystal-lang/crystal/pull/16031 [#15826]: https://github.com/crystal-lang/crystal/pull/15826 [#16001]: https://github.com/crystal-lang/crystal/pull/16001 [#15985]: https://github.com/crystal-lang/crystal/pull/15985 [#16041]: https://github.com/crystal-lang/crystal/pull/16041 ### Specs #### stdlib - _(networking)_ Disable UDP multicast spec on macOS ([#15990], thanks @straight-shoota) - _(networking)_ Extract specs for `HTTP::Cookies` to their own file ([#16106], thanks @straight-shoota) - _(networking)_ Overhaul `HTTP::Cookies` specs ([#16117], thanks @straight-shoota) - _(networking)_ Fix `UDPSocket` broadcast spec to not use `connect` ([#16165], thanks @ysbaddaden) - _(runtime)_ Disable flaky spec for `Fiber::ExecutionContext::GlobalQueue` on macOS ([#16146], thanks @ysbaddaden) - _(system)_ Enable specs for `close_on_exec` on Windows ([#14716], thanks @straight-shoota) [#15990]: https://github.com/crystal-lang/crystal/pull/15990 [#16106]: https://github.com/crystal-lang/crystal/pull/16106 [#16117]: https://github.com/crystal-lang/crystal/pull/16117 [#16165]: https://github.com/crystal-lang/crystal/pull/16165 [#16146]: https://github.com/crystal-lang/crystal/pull/16146 [#14716]: https://github.com/crystal-lang/crystal/pull/14716 #### compiler - Use `<<-CRYSTAL` in compiler specs consistently ([#16083], thanks @HertzDevil) - Style the remaining multi-line compiler specs using heredocs ([#16125], thanks @HertzDevil) - _(codegen)_ Style multi-line codegen specs using heredocs ([#16081], thanks @HertzDevil) - _(codegen)_ Style `test_c` codegen specs using heredocs ([#16082], thanks @HertzDevil) - _(semantic)_ Style multi-line `assert_type` specs using heredocs ([#16088], thanks @HertzDevil) - _(semantic)_ Style multi-line `assert_error` specs using heredocs ([#16093], thanks @HertzDevil) - _(semantic)_ Move `crystal_path_spec` fixtures to `spec/compiler/data` ([#16086], thanks @straight-shoota) [#16083]: https://github.com/crystal-lang/crystal/pull/16083 [#16125]: https://github.com/crystal-lang/crystal/pull/16125 [#16081]: https://github.com/crystal-lang/crystal/pull/16081 [#16082]: https://github.com/crystal-lang/crystal/pull/16082 [#16088]: https://github.com/crystal-lang/crystal/pull/16088 [#16093]: https://github.com/crystal-lang/crystal/pull/16093 [#16086]: https://github.com/crystal-lang/crystal/pull/16086 #### tools - _(formatter)_ Add specs for `x.[](y)` syntax ([#16109], thanks @straight-shoota) [#16109]: https://github.com/crystal-lang/crystal/pull/16109 ### Infrastructure - Changelog for 1.18.0 ([#16153], thanks @straight-shoota) - Update previous Crystal release 1.17.0 ([#15988], thanks @straight-shoota) - Support debug builds for the MSVC Boehm GC libraries ([#15968], thanks @HertzDevil) - Fix funding.json well-known file name ([#16000], thanks @matiasgarciaisaia) - Lint the Bash auto-completion script ([#15993], thanks @HertzDevil) - Merge `release/1.17`@`1.17.1` into `master` ([#16017], thanks @straight-shoota) - Update previous Crystal release 1.17.1 ([#16016], thanks @straight-shoota) - Add new types to GitHub issue templates ([#15811], thanks @straight-shoota) - Disable ameba rule `Lint/Formatting` ([#16015], thanks @straight-shoota) - Add `REUSE.toml` ([#15992], thanks @straight-shoota) - Default to LLVM 16 in `shell.nix` ([#16023], thanks @ysbaddaden) - Avoid updating `forward-compatibility.yml` on release update for patch releases ([#16019], thanks @straight-shoota) - Disable `Lint/LiteralsComparison` in more spec files ([#16087], thanks @straight-shoota) - Fix typo in Makefile comment ([#16126], thanks @kojix2) - Fix duplicate `--error-trace` option in man page ([#16133], thanks @kojix2) - Makefile: Skip grisu3 float printer deprecations in `std_spec` ([#16185], thanks @ysbaddaden) - Fix changelog format for Markdown linter ([#16188], thanks @straight-shoota) - _(ci)_ Add `fail-fast: false` for strategy CI jobs ([#15960], thanks @straight-shoota) - _(ci)_ Add tests for latest OpenSSL and LibreSSL in Alpine edge ([#15812], thanks @straight-shoota) - _(ci)_ Use MSYS2 Crystal package for ARM64 Windows CI ([#15991], thanks @HertzDevil) - _(ci)_ Add macos-15 runner ([#15982], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#16067], thanks @renovate) - _(ci)_ Update GH Actions ([#16084], thanks @renovate) - _(ci)_ Update crate-ci/typos action to v1.35.5 ([#16102], thanks @renovate) - _(ci)_ Update GH Actions ([#16131], thanks @renovate) - _(ci)_ Update deprecated `macos-13` to `macos-15-intel` ([#16197], thanks @straight-shoota) - _(ci)_ Trigger LLVM CI when codegen files are changed ([#16116], thanks @HertzDevil) - _(ci)_ Do not use D drive on MSVC CI ([#15986], thanks @HertzDevil) [#16153]: https://github.com/crystal-lang/crystal/pull/16153 [#15988]: https://github.com/crystal-lang/crystal/pull/15988 [#15968]: https://github.com/crystal-lang/crystal/pull/15968 [#16000]: https://github.com/crystal-lang/crystal/pull/16000 [#15993]: https://github.com/crystal-lang/crystal/pull/15993 [#16017]: https://github.com/crystal-lang/crystal/pull/16017 [#16016]: https://github.com/crystal-lang/crystal/pull/16016 [#15811]: https://github.com/crystal-lang/crystal/pull/15811 [#16015]: https://github.com/crystal-lang/crystal/pull/16015 [#15992]: https://github.com/crystal-lang/crystal/pull/15992 [#16023]: https://github.com/crystal-lang/crystal/pull/16023 [#16019]: https://github.com/crystal-lang/crystal/pull/16019 [#16087]: https://github.com/crystal-lang/crystal/pull/16087 [#16126]: https://github.com/crystal-lang/crystal/pull/16126 [#16133]: https://github.com/crystal-lang/crystal/pull/16133 [#16185]: https://github.com/crystal-lang/crystal/pull/16185 [#16188]: https://github.com/crystal-lang/crystal/pull/16188 [#15960]: https://github.com/crystal-lang/crystal/pull/15960 [#15812]: https://github.com/crystal-lang/crystal/pull/15812 [#15991]: https://github.com/crystal-lang/crystal/pull/15991 [#15982]: https://github.com/crystal-lang/crystal/pull/15982 [#16067]: https://github.com/crystal-lang/crystal/pull/16067 [#16084]: https://github.com/crystal-lang/crystal/pull/16084 [#16102]: https://github.com/crystal-lang/crystal/pull/16102 [#16131]: https://github.com/crystal-lang/crystal/pull/16131 [#16197]: https://github.com/crystal-lang/crystal/pull/16197 [#16116]: https://github.com/crystal-lang/crystal/pull/16116 [#15986]: https://github.com/crystal-lang/crystal/pull/15986 ================================================ FILE: doc/changelogs/v1.19.md ================================================ # Changelog 1.19 ## [1.19.1] (2026-01-20) [1.19.1]: https://github.com/crystal-lang/crystal/releases/1.19.1 ### Bugfixes #### stdlib - _(concurrency)_ **[regression]** Fix kqueue timer duration calculation ([#16581], thanks @skuznetsov) - _(concurrency)_ **[regression]** time calculations in IOCP and Monitor thread ([#16583], thanks @ysbaddaden) [#16581]: https://github.com/crystal-lang/crystal/pull/16581 [#16583]: https://github.com/crystal-lang/crystal/pull/16583 ### Infrastructure - Changelog for 1.19.1 ([#16590], thanks @ysbaddaden) [#16590]: https://github.com/crystal-lang/crystal/pull/16589 ## [1.19.0] (2026-01-14) [1.19.0]: https://github.com/crystal-lang/crystal/releases/1.19.0 ### Breaking changes #### stdlib - _(crypto)_ Require OpenSSL 1.1.1+ or LibreSSL 3+ ([#16480], thanks @ysbaddaden) [#16480]: https://github.com/crystal-lang/crystal/pull/16480 ### Features #### lang - _(macros)_ **[breaking]** Add compiler flag values ([#16310], thanks @straight-shoota) - _(macros)_ Add yielding variant of `StringLiteral#gsub` ([#16378], thanks @Blacksmoke16) - _(macros)_ Support `StringLiteral#split(RegexLiteral)` ([#16423], thanks @HertzDevil) - _(macros)_ Add `StringLiteral#match` ([#16464], thanks @HertzDevil) - _(macros)_ Make all overloads of `ArrayLiteral#[]` return `nil` on out of bounds ([#16453], thanks @HertzDevil) [#16310]: https://github.com/crystal-lang/crystal/pull/16310 [#16378]: https://github.com/crystal-lang/crystal/pull/16378 [#16423]: https://github.com/crystal-lang/crystal/pull/16423 [#16464]: https://github.com/crystal-lang/crystal/pull/16464 [#16453]: https://github.com/crystal-lang/crystal/pull/16453 #### stdlib - _(collection)_ Add `NamedTuple#reverse_merge` ([#16229], thanks @andrykonchin) - _(collection)_ Pad `Hash#inspect`, `Tuple#inspect` before `{` from first element ([#16245], thanks @andrykonchin) - _(collection)_ Add `Set#map!` ([#16271], thanks @andrykonchin) - _(collection)_ Add `Hash#transform_keys!` ([#16280], thanks @andrykonchin) - _(collection)_ Enhance error message for `Hash#[]` when key is wrong type for default block ([#16442], thanks @Blacksmoke16) - _(concurrency)_ Add `Sync::Mutex` and `Sync::RWLock` ([#16399], thanks @ysbaddaden) - _(concurrency)_ Add `Sync::ConditionVariable` ([#16440], thanks @ysbaddaden) - _(concurrency)_ Import `Sync::Exclusive` and `Sync::Shared` ([#16487], thanks @ysbaddaden) - _(crypto)_ Add `OpenSSL::SSL::Context::Server#on_server_name` for SNI ([#16452], [#16525], thanks @carlhoerberg, @straight-shoota) - _(networking)_ Loosen type restrictions in `StaticFileHandler` helper methods from `File` to `IO` ([#16238], thanks @andrykonchin) - _(networking)_ Add `IPSocket#ipv6_only` ([#16347], thanks @stakach) - _(networking)_ Expose `flags` hint for `getaddrinfo` ([#16528], thanks @stakach) - _(numeric)_ Add `Int.from_digits` as inverse of `Int#digits` ([#16237], [#16566], thanks @andrykonchin, @ysbaddaden) - _(numeric)_ Add `BigInt.from_digits` ([#16259], thanks @HertzDevil) - _(numeric)_ Add `Int#tdivmod` ([#16258], thanks @andrykonchin) - _(runtime)_ Add `Proc#[]` as alias to `#call` ([#16220], thanks @andrykonchin) - _(runtime)_ Add `#unshift`, `#pop` and `#pop?` to `Crystal::PointerLinkedList` ([#16287], thanks @ysbaddaden) - _(runtime)_ Add `Random.next_bool` and `.next_int` ([#16297], thanks @ysbaddaden) - _(runtime)_ Add `Random#split` and `#split_internal` API for splittable PRNGs ([#16342], [#16495], thanks @ysbaddaden) - _(runtime)_ Add `Pointer#fill` ([#16338], thanks @straight-shoota) - _(runtime)_ Add `Crystal::PointerLinkedList#first?` ([#16400], thanks @ysbaddaden) - _(runtime)_ Ensure single reader and writer to system fd on Unix ([#16209], thanks @ysbaddaden) - _(runtime)_ Protect `Box.unbox` from dereferencing null pointer ([#16514], thanks @straight-shoota) - _(runtime)_ Register execution context schedulers with the event loop ([#16519], thanks @ysbaddaden) - _(runtime)_ Add `Fiber::ExecutionContext::Scheduler.current?` ([#16521], thanks @ysbaddaden) - _(runtime)_ Move execution context event loop lock to each event loop ([#16520], thanks @ysbaddaden) - _(serialization)_ Support deserialization of YAML anchors of value types ([#16186], thanks @HertzDevil) - _(serialization)_ Add end locations to scalars and aliases in `YAML::Nodes.parse` ([#16187], thanks @HertzDevil) - _(serialization)_ Set `JSON::SerializableError#attribute` when appropriate ([#16158], thanks @spuun) - _(serialization)_ Support large JSON files ([#16211], thanks @RX14) - _(serialization)_ Add `YAML::Nodes.parse_all` ([#16247], thanks @HertzDevil) - _(specs)_ Rescale execution context in spec runner with `CRYSTAL_WORKERS` ([#16444], [#16471], thanks @straight-shoota, @ysbaddaden) - _(system)_ Add `Process.debugger_present?` for Windows and Linux ([#16248], thanks @HertzDevil) - _(system)_ Implement `execvpe_impl` ([#16322], [#16344], thanks @straight-shoota) - _(system)_ Add `::exit(Process::Status)` ([#16436], thanks @straight-shoota) - _(system)_ Standardize system error codes for `File::Error` ([#16024], thanks @straight-shoota) - _(system)_ Add `Path#relative?` ([#16473], thanks @Sija) - _(text)_ PCRE2: use thread local for jit stack and match data ([#16175], thanks @ysbaddaden) - _(text)_ Support 0X, 0O, 0B prefixes in string to integer conversion ([#16226], thanks @andrykonchin) - _(text)_ Add `String#each_line` parameter `remove_empty` ([#16232], thanks @andrykonchin) - _(time)_ Add `weeks` parameter to `Time::Span.new` ([#16208], thanks @Sija) - _(time)_ Treat GMT as a legacy alias of UTC ([#16292], thanks @straight-shoota) - _(time)_ Add `/etc/zoneinfo` to zoneinfo lookup paths ([#16463], thanks @straight-shoota) - _(time)_ Add support for `$TZDIR` ([#16466], thanks @straight-shoota) - _(time)_ Add `Time::Instant` ([#16490], thanks @straight-shoota) - _(time)_ **[breaking]** Adjust monotonic clocks to include suspended time with precision ([#16516], thanks @straight-shoota) [#16229]: https://github.com/crystal-lang/crystal/pull/16229 [#16245]: https://github.com/crystal-lang/crystal/pull/16245 [#16271]: https://github.com/crystal-lang/crystal/pull/16271 [#16280]: https://github.com/crystal-lang/crystal/pull/16280 [#16442]: https://github.com/crystal-lang/crystal/pull/16442 [#16399]: https://github.com/crystal-lang/crystal/pull/16399 [#16440]: https://github.com/crystal-lang/crystal/pull/16440 [#16487]: https://github.com/crystal-lang/crystal/pull/16487 [#16452]: https://github.com/crystal-lang/crystal/pull/16452 [#16525]: https://github.com/crystal-lang/crystal/pull/16525 [#16238]: https://github.com/crystal-lang/crystal/pull/16238 [#16347]: https://github.com/crystal-lang/crystal/pull/16347 [#16528]: https://github.com/crystal-lang/crystal/pull/16528 [#16237]: https://github.com/crystal-lang/crystal/pull/16237 [#16566]: https://github.com/crystal-lang/crystal/pull/16566 [#16259]: https://github.com/crystal-lang/crystal/pull/16259 [#16258]: https://github.com/crystal-lang/crystal/pull/16258 [#16220]: https://github.com/crystal-lang/crystal/pull/16220 [#16287]: https://github.com/crystal-lang/crystal/pull/16287 [#16297]: https://github.com/crystal-lang/crystal/pull/16297 [#16342]: https://github.com/crystal-lang/crystal/pull/16342 [#16495]: https://github.com/crystal-lang/crystal/pull/16495 [#16338]: https://github.com/crystal-lang/crystal/pull/16338 [#16400]: https://github.com/crystal-lang/crystal/pull/16400 [#16209]: https://github.com/crystal-lang/crystal/pull/16209 [#16514]: https://github.com/crystal-lang/crystal/pull/16514 [#16519]: https://github.com/crystal-lang/crystal/pull/16519 [#16521]: https://github.com/crystal-lang/crystal/pull/16521 [#16520]: https://github.com/crystal-lang/crystal/pull/16520 [#16186]: https://github.com/crystal-lang/crystal/pull/16186 [#16187]: https://github.com/crystal-lang/crystal/pull/16187 [#16158]: https://github.com/crystal-lang/crystal/pull/16158 [#16211]: https://github.com/crystal-lang/crystal/pull/16211 [#16247]: https://github.com/crystal-lang/crystal/pull/16247 [#16444]: https://github.com/crystal-lang/crystal/pull/16444 [#16471]: https://github.com/crystal-lang/crystal/pull/16471 [#16248]: https://github.com/crystal-lang/crystal/pull/16248 [#16322]: https://github.com/crystal-lang/crystal/pull/16322 [#16344]: https://github.com/crystal-lang/crystal/pull/16344 [#16436]: https://github.com/crystal-lang/crystal/pull/16436 [#16024]: https://github.com/crystal-lang/crystal/pull/16024 [#16473]: https://github.com/crystal-lang/crystal/pull/16473 [#16175]: https://github.com/crystal-lang/crystal/pull/16175 [#16226]: https://github.com/crystal-lang/crystal/pull/16226 [#16232]: https://github.com/crystal-lang/crystal/pull/16232 [#16208]: https://github.com/crystal-lang/crystal/pull/16208 [#16292]: https://github.com/crystal-lang/crystal/pull/16292 [#16463]: https://github.com/crystal-lang/crystal/pull/16463 [#16466]: https://github.com/crystal-lang/crystal/pull/16466 [#16490]: https://github.com/crystal-lang/crystal/pull/16490 [#16516]: https://github.com/crystal-lang/crystal/pull/16516 #### compiler - _(codegen)_ Build compiler with `-Dexecution_context` ([#16447], [#16502], thanks @ysbaddaden, @straight-shoota) - _(interpreter)_ Support `->LibX.fun_name` in the interpreter ([#16194], thanks @ysbaddaden) - _(semantic)_ Add error message to `CrystalPath::NotFoundError` ([#16365], thanks @willhbr) - _(semantic)_ Retain original location for errors in `included`, `extended` hooks ([#13261], thanks @Blacksmoke16) [#16447]: https://github.com/crystal-lang/crystal/pull/16447 [#16502]: https://github.com/crystal-lang/crystal/pull/16502 [#16194]: https://github.com/crystal-lang/crystal/pull/16194 [#16365]: https://github.com/crystal-lang/crystal/pull/16365 [#13261]: https://github.com/crystal-lang/crystal/pull/13261 #### tools - _(docs-generator)_ Add optional sanitizer to docs generator ([#14646], [#16251], thanks @nobodywasishere, @straight-shoota) [#14646]: https://github.com/crystal-lang/crystal/pull/14646 [#16251]: https://github.com/crystal-lang/crystal/pull/16251 ### Bugfixes #### lang - _(macros)_ Fix nested sigil delimiter parsing inside macros ([#16266], thanks @HertzDevil) [#16266]: https://github.com/crystal-lang/crystal/pull/16266 #### stdlib - Fix `OptionParser` subcommand help to respect custom `summary_indent` ([#16334], thanks @kojix2) - _(collection)_ Fix `Hash` methods to retain `compare_by_identity` flag ([#16356], thanks @andrykonchin) - _(collection)_ Fix Hash methods and retaining default value ([#16374], thanks @andrykonchin) - _(files)_ Fix condition for no-op `lock_write` to work without sockets ([#16304], thanks @straight-shoota) - _(networking)_ Fix `HTTP::Cookie` parsing trailing semicolons ([#16328], thanks @alexkutsan) - _(networking)_ **[breaking]** Make `#flush` in `WebSocket#stream` a no-op to not send wrongly frames ([#16539], thanks @spuun) - _(runtime)_ **[deprecation]** Add thread safety to default random ([#16174], [#16568], thanks @ysbaddaden) - _(runtime)_ default execution context is `Parallel` ([#16367], thanks @ysbaddaden) - _(runtime)_ `Crystal::PointerLinkedList#each` stops iterating when deleting head ([#16401], thanks @ysbaddaden) - _(runtime)_ closing system fd is thread unsafe ([#16289], thanks @ysbaddaden) - _(runtime)_ `Crystal::System::Process#rwlock` with Crystal < 1.7 (UNIX) ([#16482], thanks @ysbaddaden) - _(runtime)_ urandom initialization isn't thread safe + refactor ([#16479], thanks @ysbaddaden) - _(runtime)_ execution context queue stress tests failures ([#16472], thanks @ysbaddaden) - _(runtime)_ don't use `Time.monotonic` in `Fiber::ExecutionContext::Monitor` ([#16500], thanks @ysbaddaden) - _(runtime)_ thread safety of `Exception::Callstack` ([#16504], thanks @ysbaddaden) - _(runtime)_ actually clear memory using gc_none on unix ([#16562], thanks @BlobCodes) - _(serialization)_ memory leak in `XML.parse` and `XML.parse_html` methods ([#16414], thanks @ysbaddaden) - _(serialization)_ memory leak in `XML::Document#finalize` ([#16418], thanks @toddsundsted) - _(serialization)_ memory leak in `XML::Node#content=` ([#16419], thanks @toddsundsted) - _(serialization)_ Fix use after unlink in `XML::Node` ([#16432], thanks @toddsundsted) - _(specs)_ Resolve inconsistent use of `#inspect` in `expect_raises` ([#16265], [#16375], thanks @andrykonchin, @straight-shoota) - _(system)_ Create `argv` before `fork` ([#16286], [#16321], thanks @straight-shoota) - _(system)_ Pass `envp` to `execvpe` ([#16340], thanks @straight-shoota) - _(system)_ Move `make_envp` before `fork` ([#16351], thanks @straight-shoota) - _(system)_ Replace `Dir.cd` with a non-raising alternative in pre-exec ([#16352], [#16369], thanks @straight-shoota) - _(system)_ Fix reset directory if `Process.exec` fails ([#16383], thanks @straight-shoota) - _(system)_ Fix reorder `Process.lock_write` outside of `.block_signals` ([#16465], thanks @straight-shoota) - _(system)_ Disable process cancellation during `fork` ([#16446], thanks @straight-shoota) [#16334]: https://github.com/crystal-lang/crystal/pull/16334 [#16356]: https://github.com/crystal-lang/crystal/pull/16356 [#16374]: https://github.com/crystal-lang/crystal/pull/16374 [#16304]: https://github.com/crystal-lang/crystal/pull/16304 [#16328]: https://github.com/crystal-lang/crystal/pull/16328 [#16539]: https://github.com/crystal-lang/crystal/pull/16539 [#16174]: https://github.com/crystal-lang/crystal/pull/16174 [#16568]: https://github.com/crystal-lang/crystal/pull/16568 [#16367]: https://github.com/crystal-lang/crystal/pull/16367 [#16401]: https://github.com/crystal-lang/crystal/pull/16401 [#16289]: https://github.com/crystal-lang/crystal/pull/16289 [#16482]: https://github.com/crystal-lang/crystal/pull/16482 [#16479]: https://github.com/crystal-lang/crystal/pull/16479 [#16472]: https://github.com/crystal-lang/crystal/pull/16472 [#16500]: https://github.com/crystal-lang/crystal/pull/16500 [#16504]: https://github.com/crystal-lang/crystal/pull/16504 [#16562]: https://github.com/crystal-lang/crystal/pull/16562 [#16414]: https://github.com/crystal-lang/crystal/pull/16414 [#16418]: https://github.com/crystal-lang/crystal/pull/16418 [#16419]: https://github.com/crystal-lang/crystal/pull/16419 [#16432]: https://github.com/crystal-lang/crystal/pull/16432 [#16265]: https://github.com/crystal-lang/crystal/pull/16265 [#16375]: https://github.com/crystal-lang/crystal/pull/16375 [#16286]: https://github.com/crystal-lang/crystal/pull/16286 [#16321]: https://github.com/crystal-lang/crystal/pull/16321 [#16340]: https://github.com/crystal-lang/crystal/pull/16340 [#16351]: https://github.com/crystal-lang/crystal/pull/16351 [#16352]: https://github.com/crystal-lang/crystal/pull/16352 [#16369]: https://github.com/crystal-lang/crystal/pull/16369 [#16383]: https://github.com/crystal-lang/crystal/pull/16383 [#16465]: https://github.com/crystal-lang/crystal/pull/16465 [#16446]: https://github.com/crystal-lang/crystal/pull/16446 #### compiler - _(cli)_ chore: correct progress step count to 14 ([#16269], thanks @miry) - _(codegen)_ Fix System V ABI for arrays of packed structs with misaligned fields ([#16314], thanks @HertzDevil) - _(debugger)_ Fix debug info for closured variables ([#16393], thanks @HertzDevil) - _(interpreter)_ interpreter handles `self` in inlined method with arguments ([#16307], thanks @cyangle) - _(interpreter)_ interpreter `typeof` should return concrete type ([#16379], thanks @cyangle) - _(interpreter)_ Fix variable shadowing bug in interpreter ([#16335], thanks @cyangle) - _(interpreter)_ interpreter musn't reuse dead fiber stacks ([#16518], thanks @ysbaddaden) - _(parser)_ Fix internal error if multi-assign RHS has splats ([#16182], thanks @HertzDevil) - _(parser)_ Fix regex delimiter detection in syntax highlighter ([#16394], thanks @HertzDevil) - _(parser)_ Merge adjacent StringLiterals before yielding ([#16427], thanks @Blacksmoke16) - _(parser)_ Fix `Call#end_location` w/ named arguments off-by-one error ([#16542], thanks @Sija) - _(parser)_ Fix incorrect location for parenthesized union AST nodes ([#16552], thanks @Sija) - _(semantic)_ Fix instantiation of abstract generic structs in virtual type lookup ([#16513], thanks @Blacksmoke16) - _(semantic)_ Fix variables assigned inside `&&` conditions with method calls incorrectly got `Nil` added to their type ([#16512], thanks @Blacksmoke16) [#16269]: https://github.com/crystal-lang/crystal/pull/16269 [#16314]: https://github.com/crystal-lang/crystal/pull/16314 [#16393]: https://github.com/crystal-lang/crystal/pull/16393 [#16307]: https://github.com/crystal-lang/crystal/pull/16307 [#16379]: https://github.com/crystal-lang/crystal/pull/16379 [#16335]: https://github.com/crystal-lang/crystal/pull/16335 [#16518]: https://github.com/crystal-lang/crystal/pull/16518 [#16182]: https://github.com/crystal-lang/crystal/pull/16182 [#16394]: https://github.com/crystal-lang/crystal/pull/16394 [#16427]: https://github.com/crystal-lang/crystal/pull/16427 [#16542]: https://github.com/crystal-lang/crystal/pull/16542 [#16552]: https://github.com/crystal-lang/crystal/pull/16552 [#16513]: https://github.com/crystal-lang/crystal/pull/16513 [#16512]: https://github.com/crystal-lang/crystal/pull/16512 #### tools - _(docs-generator)_ Fix doc generation when nesting multiple `:inherit:` directives ([#16443], thanks @Blacksmoke16) - _(docs-generator)_ Fix some doc inconsistencies for macros ([#16561], thanks @Blacksmoke16) - _(formatter)_ Fix incorrect formatting of multi-line macro expression with comment as first line ([#16429], thanks @Blacksmoke16) - _(formatter)_ Add multi-line formatting support to `Generic` formatter visitor ([#16430], thanks @Blacksmoke16) [#16443]: https://github.com/crystal-lang/crystal/pull/16443 [#16561]: https://github.com/crystal-lang/crystal/pull/16561 [#16429]: https://github.com/crystal-lang/crystal/pull/16429 [#16430]: https://github.com/crystal-lang/crystal/pull/16430 ### Chores #### lang - _(macros)_ **[deprecation]** Deprecate single-letter macro fresh variables with indices ([#16267], thanks @HertzDevil) - _(macros)_ **[deprecation]** Deprecate macro fresh variables with constant names ([#16293], thanks @HertzDevil) [#16267]: https://github.com/crystal-lang/crystal/pull/16267 [#16293]: https://github.com/crystal-lang/crystal/pull/16293 #### stdlib - _(macros)_ **[deprecation]** Deprecate `StringLiteral#split(ASTNode)` for non-separator arguments ([#16439], thanks @HertzDevil) - _(time)_ **[deprecation]** Deprecate `Time#inspect(io, *, with_nanoseconds)` ([#16416], thanks @straight-shoota) - _(time)_ **[deprecation]** Deprecate `Time.monotonic` ([#16545], thanks @straight-shoota) [#16439]: https://github.com/crystal-lang/crystal/pull/16439 [#16416]: https://github.com/crystal-lang/crystal/pull/16416 [#16545]: https://github.com/crystal-lang/crystal/pull/16545 #### compiler - _(cli)_ Error when trying to build aarch64 with LLVM 12 and below ([#15018], thanks @straight-shoota) [#15018]: https://github.com/crystal-lang/crystal/pull/15018 #### other - Update copyright year ([#16550], thanks @HertzDevil) - Remove redundant `begin`/`end` blocks ([#16554], thanks @straight-shoota) [#16550]: https://github.com/crystal-lang/crystal/pull/16550 [#16554]: https://github.com/crystal-lang/crystal/pull/16554 ### Performance #### stdlib - Avoid calling `times.map` ([#16422], thanks @HertzDevil) - _(runtime)_ Skip initialization of `Pointer.malloc` with zero value ([#16333], thanks @straight-shoota) - _(runtime)_ Call `Pointer.malloc(size, value)` in `Slice.new(size, value)` ([#16358], thanks @straight-shoota) [#16422]: https://github.com/crystal-lang/crystal/pull/16422 [#16333]: https://github.com/crystal-lang/crystal/pull/16333 [#16358]: https://github.com/crystal-lang/crystal/pull/16358 #### compiler - Group temporary variables by file name: splats ([#16242], thanks @HertzDevil) - _(codegen)_ **[regression]** Only define the type name table in the main LLVM module ([#16260], thanks @HertzDevil) - _(codegen)_ Allow closures to use atomic allocation ([#16360], thanks @HertzDevil) [#16242]: https://github.com/crystal-lang/crystal/pull/16242 [#16260]: https://github.com/crystal-lang/crystal/pull/16260 [#16360]: https://github.com/crystal-lang/crystal/pull/16360 ### Refactor #### stdlib - Refactor flag and value parsing into a separate method ([#16300], thanks @straight-shoota) - _(cli)_ Refactor `OptionParser#parse` ([#16233], thanks @kojix2) - _(cli)_ Simplify `OptionParser#handle_flag` with guard clauses ([#16309], thanks @kojix2) - _(files)_ Fix: don't flush twice in `File#truncate` (UNIX) ([#16395], thanks @ysbaddaden) - _(llvm)_ simplify target initialization and support more targets ([#16437], thanks @ysbaddaden) - _(log)_ `Log::Metadata` should put parent entries first on extend (like `Hash#merge`) ([#16098], thanks @spuun) - _(networking)_ Split `HTTP::Headers#get(Key)` into undocumented overload ([#16283], thanks @straight-shoota) - _(networking)_ Remove internal type `OAuth::Params` ([#16319], thanks @AnandRaj2224) - _(runtime)_ Refactor `Crystal::DWARF::LineNumbers::Sequence` ([#16214], thanks @HertzDevil) - _(runtime)_ Extract `Crystal::EventLoop#shutdown` from `#close` ([#16288], [#16366], thanks @ysbaddaden) - _(runtime)_ Prefer `Random::Secure.random_bytes` ([#16298], thanks @ysbaddaden) - _(runtime)_ Set default `random` arg to `nil` instead of `Random::DEFAULT` ([#16299], thanks @ysbaddaden) - _(runtime)_ Drop `EventLoop#after_fork_before_exec` ([#16332], thanks @straight-shoota) - _(runtime)_ Cleanup node on `Crystal::PointerLinkedList#delete` ([#16398], thanks @ysbaddaden) - _(runtime)_ Add `Fiber::Stack#size` ([#16420], thanks @ysbaddaden) - _(runtime)_ Fix: `new_thread` spec helper must return isolated context (not thread) ([#16421], thanks @ysbaddaden) - _(runtime)_ Fix: always use getrandom on Linux and Android >= 28 ([#16478], thanks @ysbaddaden) - _(system)_ Extract `Crystal::System::Env.each_pointer` on Unix ([#16200], thanks @straight-shoota) - _(system)_ Refactor internal `Crystal::System::Process#fork` on UNIX ([#16191], [#16373], thanks @ysbaddaden, @straight-shoota) - _(system)_ Use `execvpe` when available ([#16294], [#16311], thanks @straight-shoota) - _(system)_ Add `Env.make_envp` ([#16320], [#16384], thanks @straight-shoota) - _(system)_ Fix pre-exec for closed file descriptor ([#16359], thanks @straight-shoota) - _(system)_ Move `prepare_args` into system implementation internals ([#16362], thanks @straight-shoota) - _(system)_ Extract `unix/spawn.cr` as a separate file ([#16388], thanks @straight-shoota) - _(system)_ Extract internal `Process.block_signals` helper ([#16402], thanks @straight-shoota) - _(system)_ Rename target `aarch64-android` to `aarch64-linux-android` ([#16409], thanks @straight-shoota) - _(text)_ Simplify `String#byte_slice(Int)` and `String#byte_slice?(Int)` ([#16235], thanks @andrykonchin) - _(time)_ Use `clock_gettime` on darwin ([#16492], thanks @straight-shoota) - _(time)_ Add `Crystal::System::Time.instant` ([#16506], thanks @straight-shoota) - _(time)_ Replace `Time.monotonic` with `Time.instant` [follow-up #16490] ([#16498], thanks @straight-shoota) - _(time)_ remove extraneous method definition for `Time::Span#sign` ([#16553], thanks @plambert) [#16300]: https://github.com/crystal-lang/crystal/pull/16300 [#16233]: https://github.com/crystal-lang/crystal/pull/16233 [#16309]: https://github.com/crystal-lang/crystal/pull/16309 [#16395]: https://github.com/crystal-lang/crystal/pull/16395 [#16437]: https://github.com/crystal-lang/crystal/pull/16437 [#16098]: https://github.com/crystal-lang/crystal/pull/16098 [#16283]: https://github.com/crystal-lang/crystal/pull/16283 [#16319]: https://github.com/crystal-lang/crystal/pull/16319 [#16214]: https://github.com/crystal-lang/crystal/pull/16214 [#16288]: https://github.com/crystal-lang/crystal/pull/16288 [#16366]: https://github.com/crystal-lang/crystal/pull/16366 [#16298]: https://github.com/crystal-lang/crystal/pull/16298 [#16299]: https://github.com/crystal-lang/crystal/pull/16299 [#16332]: https://github.com/crystal-lang/crystal/pull/16332 [#16398]: https://github.com/crystal-lang/crystal/pull/16398 [#16420]: https://github.com/crystal-lang/crystal/pull/16420 [#16421]: https://github.com/crystal-lang/crystal/pull/16421 [#16478]: https://github.com/crystal-lang/crystal/pull/16478 [#16200]: https://github.com/crystal-lang/crystal/pull/16200 [#16191]: https://github.com/crystal-lang/crystal/pull/16191 [#16373]: https://github.com/crystal-lang/crystal/pull/16373 [#16294]: https://github.com/crystal-lang/crystal/pull/16294 [#16311]: https://github.com/crystal-lang/crystal/pull/16311 [#16320]: https://github.com/crystal-lang/crystal/pull/16320 [#16384]: https://github.com/crystal-lang/crystal/pull/16384 [#16359]: https://github.com/crystal-lang/crystal/pull/16359 [#16362]: https://github.com/crystal-lang/crystal/pull/16362 [#16388]: https://github.com/crystal-lang/crystal/pull/16388 [#16402]: https://github.com/crystal-lang/crystal/pull/16402 [#16409]: https://github.com/crystal-lang/crystal/pull/16409 [#16235]: https://github.com/crystal-lang/crystal/pull/16235 [#16492]: https://github.com/crystal-lang/crystal/pull/16492 [#16506]: https://github.com/crystal-lang/crystal/pull/16506 [#16498]: https://github.com/crystal-lang/crystal/pull/16498 [#16553]: https://github.com/crystal-lang/crystal/pull/16553 ### Documentation #### lang - _(annotations)_ Fix `@[Deprecated]` doc comment ([#16302], thanks @jgaskins) [#16302]: https://github.com/crystal-lang/crystal/pull/16302 #### stdlib - _(collection)_ Clarify `Set`'s enumeration order ([#16274], thanks @HertzDevil) - _(concurrency)_ Add docs for `Sync` namespace ([#16565], thanks @ysbaddaden) - _(crypto)_ Remove outdated performance hint in `Bcrypt` docs ([#16536], thanks @BlobCodes) - _(macros)_ Fix invalid runtime types in macro docs ([#16534], thanks @BlobCodes) - _(networking)_ Add type restrictions to `OAuth::Consumer#get_authorize_uri` ([#16285], thanks @straight-shoota) - _(numeric)_ Improve docs for `Int` to mention `Int128` and `UInt128` ([#16529], thanks @HCLarsen) - _(runtime)_ Use `to_slice` for presentation in `Pointer` doc examples ([#16345], thanks @straight-shoota) - _(system)_ Add type restrictions to process ([#16065], thanks @Vici37) - _(text)_ Document `String#split(Regex)`'s capture group behavior ([#16207], thanks @HertzDevil) - _(text)_ Add type restrictions to regex directory ([#16066], thanks @Vici37) [#16274]: https://github.com/crystal-lang/crystal/pull/16274 [#16565]: https://github.com/crystal-lang/crystal/pull/16565 [#16536]: https://github.com/crystal-lang/crystal/pull/16536 [#16534]: https://github.com/crystal-lang/crystal/pull/16534 [#16285]: https://github.com/crystal-lang/crystal/pull/16285 [#16529]: https://github.com/crystal-lang/crystal/pull/16529 [#16345]: https://github.com/crystal-lang/crystal/pull/16345 [#16065]: https://github.com/crystal-lang/crystal/pull/16065 [#16207]: https://github.com/crystal-lang/crystal/pull/16207 [#16066]: https://github.com/crystal-lang/crystal/pull/16066 ### Specs #### lang - _(macros)_ Enhance specs for `flag?` macro ([#16336], thanks @straight-shoota) [#16336]: https://github.com/crystal-lang/crystal/pull/16336 #### stdlib - _(collection)_ Add specs for `Slice.new` ([#16424], thanks @straight-shoota) - _(concurrency)_ Fix thread name expectation with parallel execution context ([#16517], thanks @straight-shoota) - _(crypto)_ Fix: remove 1 second sleep in openssl/ssl/server spec ([#16454], thanks @ysbaddaden) - _(files)_ Add specs for `IO#read_bytes` with converter ([#16250], thanks @straight-shoota) - _(networking)_ Fix TCP specs to accept `EAI_NODATA` instead of `EAI_NONAME` for unresolvable hostname ([#16496], thanks @straight-shoota) - _(system)_ Add specs for `Process.run` ([#16306], [#16325], thanks @straight-shoota) - _(time)_ Update zoneinfo to TZDB version 2025c ([#16501], thanks @straight-shoota) [#16424]: https://github.com/crystal-lang/crystal/pull/16424 [#16517]: https://github.com/crystal-lang/crystal/pull/16517 [#16454]: https://github.com/crystal-lang/crystal/pull/16454 [#16250]: https://github.com/crystal-lang/crystal/pull/16250 [#16496]: https://github.com/crystal-lang/crystal/pull/16496 [#16306]: https://github.com/crystal-lang/crystal/pull/16306 [#16325]: https://github.com/crystal-lang/crystal/pull/16325 [#16501]: https://github.com/crystal-lang/crystal/pull/16501 #### compiler - _(semantic)_ Drop `assert_expand_second` and `assert_expand_third` helpers ([#16244], thanks @HertzDevil) [#16244]: https://github.com/crystal-lang/crystal/pull/16244 ### Infrastructure - Changelog for 1.19.0 ([#16510], thanks @ysbaddaden) - Update previous Crystal release 1.18.1 ([#16212], thanks @matiasgarciaisaia) - Fix shellcheck violations ([#16221], thanks @straight-shoota) - Fix markdownlint violations ([#16222], [#16252], thanks @straight-shoota) - Merge `release/1.18`@`1.18.2` into `master` ([#16246], thanks @straight-shoota) - Enable ameba rule `Lint/SpecFilename` ([#16223], thanks @straight-shoota) - Encourage +1 reactions on issues and PRs for prioritization ([#16241], thanks @straight-shoota) - Update previous Crystal release 1.18.2 ([#16249], thanks @straight-shoota) - Add `devenv` ([#16263], thanks @straight-shoota) - Add `ameba` to `git-hooks` ([#16276], [#16295], thanks @straight-shoota) - Add `devenv` profile `lint` ([#16291], thanks @straight-shoota) - Update distribution-scripts ([#16301], thanks @straight-shoota) - Makefile: Extract variable `COMPILER_FLAGS` ([#16349], [#16372], thanks @straight-shoota) - Fix `shell.nix` on Linux ([#16346], thanks @straight-shoota) - Build compiler with `-Dpreview_mt` ([#16380], thanks @straight-shoota) - Update `devenv.lock` ([#16386], thanks @github-actions) - Update `devenv.lock` ([#16408], thanks @github-actions) - Drop committed `.envrc` ([#16462], thanks @straight-shoota) - Add git-hook to ensure changing both `Makefile` and `Makefile.win` at the same time ([#16503], thanks @straight-shoota) - Makefile: Use simply expanded variables to avoid costly duplicate evaluation ([#16509], thanks @straight-shoota) - Fix `scripts/update-shards.sh` ([#16524], thanks @straight-shoota) - Update distribution-scripts ([#16530], thanks @straight-shoota) - Update shards 0.20.0 ([#16523], thanks @straight-shoota) - Update typos 1.38.1 ([#16219], thanks @straight-shoota) - Build snap arm64 target + drop publish_snap target ([#16491], thanks @ysbaddaden) - _(ci)_ Update darwin jobs in circleci to `m4pro.medium` resource class ([#16389], thanks @straight-shoota) - _(ci)_ Update xcode to 26.0.1 on circleci ([#16201], thanks @straight-shoota) - _(ci)_ Update korthout/backport-action action to v3.4.1 ([#16215], thanks @renovate) - _(ci)_ **[security]** Pin GitHub action uses to commit hash ([#16253], thanks @straight-shoota) - _(ci)_ Add lint workflow running `pre-commit` ([#16275], [#16296], thanks @straight-shoota) - _(ci)_ Fix issues in GHA workflows ([#16282], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#16290], thanks @renovate) - _(ci)_ Update crate-ci/typos action to v1.39.0 ([#16326], thanks @renovate) - _(ci)_ Refactor matrix configuration in Linux workflow ([#16331], thanks @straight-shoota) - _(ci)_ Reduce smoke tests to building only `std_spec` ([#16337], thanks @straight-shoota) - _(ci)_ Merge gnu and musl tests into a single matrix ([#16341], thanks @straight-shoota) - _(ci)_ Fix `pull_request` trigger for `smoke` workflow ([#16343], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#16385], thanks @renovate) - _(ci)_ Add workflow `update-devenv` ([#16387], thanks @straight-shoota) - _(ci)_ Update GH Actions ([#16434], thanks @renovate) - _(ci)_ Update distribution-scripts ([#16411], thanks @straight-shoota) - _(ci)_ Run smoke tests on docker images ([#16441], thanks @straight-shoota) - _(ci)_ Update actions/checkout digest to 8e8c483 ([#16474], thanks @renovate) - _(ci)_ Remove `test_dist_linux_on_docker` job ([#16410], thanks @straight-shoota) - _(ci)_ Push docker images directly to registry ([#16488], thanks @straight-shoota) - _(ci)_ Enable multiarch docker builds ([#16493], thanks @straight-shoota) - _(ci)_ Run multi-threading test job with execution context ([#16339], thanks @straight-shoota) - _(ci)_ build linux aarch64 tarballs ([#16330], thanks @ysbaddaden) [#16510]: https://github.com/crystal-lang/crystal/pull/16510 [#16212]: https://github.com/crystal-lang/crystal/pull/16212 [#16221]: https://github.com/crystal-lang/crystal/pull/16221 [#16222]: https://github.com/crystal-lang/crystal/pull/16222 [#16252]: https://github.com/crystal-lang/crystal/pull/16252 [#16246]: https://github.com/crystal-lang/crystal/pull/16246 [#16223]: https://github.com/crystal-lang/crystal/pull/16223 [#16241]: https://github.com/crystal-lang/crystal/pull/16241 [#16249]: https://github.com/crystal-lang/crystal/pull/16249 [#16263]: https://github.com/crystal-lang/crystal/pull/16263 [#16276]: https://github.com/crystal-lang/crystal/pull/16276 [#16295]: https://github.com/crystal-lang/crystal/pull/16295 [#16291]: https://github.com/crystal-lang/crystal/pull/16291 [#16301]: https://github.com/crystal-lang/crystal/pull/16301 [#16349]: https://github.com/crystal-lang/crystal/pull/16349 [#16372]: https://github.com/crystal-lang/crystal/pull/16372 [#16346]: https://github.com/crystal-lang/crystal/pull/16346 [#16380]: https://github.com/crystal-lang/crystal/pull/16380 [#16386]: https://github.com/crystal-lang/crystal/pull/16386 [#16408]: https://github.com/crystal-lang/crystal/pull/16408 [#16462]: https://github.com/crystal-lang/crystal/pull/16462 [#16503]: https://github.com/crystal-lang/crystal/pull/16503 [#16509]: https://github.com/crystal-lang/crystal/pull/16509 [#16524]: https://github.com/crystal-lang/crystal/pull/16524 [#16530]: https://github.com/crystal-lang/crystal/pull/16530 [#16523]: https://github.com/crystal-lang/crystal/pull/16523 [#16219]: https://github.com/crystal-lang/crystal/pull/16219 [#16491]: https://github.com/crystal-lang/crystal/pull/16491 [#16389]: https://github.com/crystal-lang/crystal/pull/16389 [#16201]: https://github.com/crystal-lang/crystal/pull/16201 [#16215]: https://github.com/crystal-lang/crystal/pull/16215 [#16253]: https://github.com/crystal-lang/crystal/pull/16253 [#16275]: https://github.com/crystal-lang/crystal/pull/16275 [#16296]: https://github.com/crystal-lang/crystal/pull/16296 [#16282]: https://github.com/crystal-lang/crystal/pull/16282 [#16290]: https://github.com/crystal-lang/crystal/pull/16290 [#16326]: https://github.com/crystal-lang/crystal/pull/16326 [#16331]: https://github.com/crystal-lang/crystal/pull/16331 [#16337]: https://github.com/crystal-lang/crystal/pull/16337 [#16341]: https://github.com/crystal-lang/crystal/pull/16341 [#16343]: https://github.com/crystal-lang/crystal/pull/16343 [#16385]: https://github.com/crystal-lang/crystal/pull/16385 [#16387]: https://github.com/crystal-lang/crystal/pull/16387 [#16434]: https://github.com/crystal-lang/crystal/pull/16434 [#16411]: https://github.com/crystal-lang/crystal/pull/16411 [#16441]: https://github.com/crystal-lang/crystal/pull/16441 [#16474]: https://github.com/crystal-lang/crystal/pull/16474 [#16410]: https://github.com/crystal-lang/crystal/pull/16410 [#16488]: https://github.com/crystal-lang/crystal/pull/16488 [#16493]: https://github.com/crystal-lang/crystal/pull/16493 [#16339]: https://github.com/crystal-lang/crystal/pull/16339 [#16330]: https://github.com/crystal-lang/crystal/pull/16330 ================================================ FILE: doc/changelogs/v1.2.md ================================================ # Changelog 1.2 ## [1.2.2] - 2021-11-10 [1.2.2]: https://github.com/crystal-lang/crystal/releases/1.2.2 ### Compiler - x86_64 ABI: pass structs indirectly if there are no more available registers ([#11344](https://github.com/crystal-lang/crystal/pull/11344), thanks @ggiraldez) - Add parentheses around type name for metaclasses of unions ([#11315](https://github.com/crystal-lang/crystal/pull/11315), thanks @HertzDevil) - **(regression)** Restrict virtual metaclasses to themselves against `Class` ([#11377](https://github.com/crystal-lang/crystal/pull/11377), thanks @HertzDevil) - **(regression)** Add fallback for union debug type if current debug file is not set ([#11390](https://github.com/crystal-lang/crystal/pull/11390), thanks @maxfierke) - **(regression)** Add missing debug locations to constant / class variable read calls ([#11417](https://github.com/crystal-lang/crystal/pull/11417), thanks @HertzDevil) ### Standard Library #### Collection - Fix `BitArray#toggle` when toggling empty subrange ([#11381](https://github.com/crystal-lang/crystal/pull/11381), thanks @HertzDevil) #### Crypto - Update for OpenSSL 3.0.0 ([#11360](https://github.com/crystal-lang/crystal/pull/11360), thanks @straight-shoota) - Restore libressl support and add CI for that ([#11400](https://github.com/crystal-lang/crystal/pull/11400), thanks @straight-shoota) - Replace lib version comparisons by functional feature checks ([#11374](https://github.com/crystal-lang/crystal/pull/11374), thanks @straight-shoota) #### Runtime - Add support for DWARF 5 ([#11399](https://github.com/crystal-lang/crystal/pull/11399), thanks @straight-shoota) - Retrieve filename of shared libs, use in stacktraces ([#11408](https://github.com/crystal-lang/crystal/pull/11408), thanks @rdp) ### Other - [CI] Fix enable nix-command as experimental feature ([#11398](https://github.com/crystal-lang/crystal/pull/11398), thanks @straight-shoota) - [CI] Fix OpenSSL 3 apk package name ([#11418](https://github.com/crystal-lang/crystal/pull/11418), thanks @straight-shoota) - Update distribution-scripts ([#11404](https://github.com/crystal-lang/crystal/pull/11404), thanks @straight-shoota) - [CI] Fix pcre download URL ([#11422](https://github.com/crystal-lang/crystal/pull/11422), thanks @straight-shoota) ## [1.2.1] - 2021-10-21 [1.2.1]: https://github.com/crystal-lang/crystal/releases/1.2.1 ### Compiler - Adding location to the Path returned by the literal expander for regex ([#11334](https://github.com/crystal-lang/crystal/pull/11334), thanks @beta-ziliani) ### Standard Library - Add support for LLVM 13 ([#11302](https://github.com/crystal-lang/crystal/pull/11302), thanks @maxfierke) #### Runtime - Move the `:nodoc:` flags to the right place to hide the `__mul*` functions. ([#11326](https://github.com/crystal-lang/crystal/pull/11326), thanks @wyhaines) ### Tools - Update markd subtree to v0.4.2 ([#11338](https://github.com/crystal-lang/crystal/pull/11338), thanks @straight-shoota) ## [1.2.0] - 2021-10-13 [1.2.0]: https://github.com/crystal-lang/crystal/releases/1.2.0 ### Compiler - Fix variance checks between generic instances for `Proc#call` and abstract defs. ([#10899](https://github.com/crystal-lang/crystal/pull/10899), thanks @HertzDevil) - Fix `proc_spec` forcing normal compilation instead of JIT ([#10964](https://github.com/crystal-lang/crystal/pull/10964), thanks @straight-shoota) - Fix `ProcNotation#to_s` remove whitespace for nil output type ([#10935](https://github.com/crystal-lang/crystal/pull/10935), thanks @straight-shoota) - Compiler: carry FileModule information inside Block ([#11039](https://github.com/crystal-lang/crystal/pull/11039), thanks @asterite) - Splat values correctly inside return/break/next statements ([#10193](https://github.com/crystal-lang/crystal/pull/10193), thanks @HertzDevil) - Handle already stripped column numbers in compiler exceptions ([#11008](https://github.com/crystal-lang/crystal/pull/11008), thanks @pyrsmk) - Substitute unbound type parameters in virtual metaclass types ([#11067](https://github.com/crystal-lang/crystal/pull/11067), thanks @HertzDevil) - Improve detection of instance variables in extended modules ([#10554](https://github.com/crystal-lang/crystal/pull/10554), thanks @HertzDevil) - Don't compute instance variable initializers on unbound generic instances ([#11000](https://github.com/crystal-lang/crystal/pull/11000), thanks @HertzDevil) - Syntax errors for invalid 128-bit integer literals ([#10975](https://github.com/crystal-lang/crystal/pull/10975), thanks @rymiel) - Support auto-splatting in captured block literals ([#10251](https://github.com/crystal-lang/crystal/pull/10251), thanks @HertzDevil) - Detect cyclic includes between generic modules ([#10529](https://github.com/crystal-lang/crystal/pull/10529), thanks @HertzDevil) - Add stricter checks for arguments to macro methods on AST nodes ([#10498](https://github.com/crystal-lang/crystal/pull/10498), thanks @HertzDevil) - Compiler: fix `is_a?` for virtual metaclass types ([#11121](https://github.com/crystal-lang/crystal/pull/11121), thanks @asterite) - Fix edge cases with unicode method names ([#10978](https://github.com/crystal-lang/crystal/pull/10978), thanks @HertzDevil) - Don't emit debug info for unused variable declarations ([#10957](https://github.com/crystal-lang/crystal/pull/10957), thanks @HertzDevil) - Fix `Call.def_full_name` print full block parameter ([#10915](https://github.com/crystal-lang/crystal/pull/10915), thanks @straight-shoota) - Allow union types to be unbound ([#11166](https://github.com/crystal-lang/crystal/pull/11166), thanks @HertzDevil) - Make `typeof` start a nested lexical scope ([#10796](https://github.com/crystal-lang/crystal/pull/10796), thanks @HertzDevil) - Fix edge case for intersection between virtual metaclasses ([#11185](https://github.com/crystal-lang/crystal/pull/11185), thanks @HertzDevil) - Compiler: don't trigger "already had enclosing call" for same object ([#11202](https://github.com/crystal-lang/crystal/pull/11202), thanks @asterite) - Properly handle indirect arguments for external C functions ([#11189](https://github.com/crystal-lang/crystal/pull/11189), thanks @ggiraldez) - Fix resolve generic argument in block output type restriction mismatch ([#11186](https://github.com/crystal-lang/crystal/pull/11186), thanks @straight-shoota) - Secure array slicing when expanding macro for stack trace ([#11109](https://github.com/crystal-lang/crystal/pull/11109), thanks @pyrsmk) - Fix debug locations for `Proc` pointers ([#11243](https://github.com/crystal-lang/crystal/pull/11243), thanks @HertzDevil) - Allow assignments from generic instance metaclasses to virtual metaclasses ([#11250](https://github.com/crystal-lang/crystal/pull/11250), thanks @HertzDevil) - Refactor `CrystalPath#find_in_path_relative_to_dir` for readability ([#10876](https://github.com/crystal-lang/crystal/pull/10876), [#10990](https://github.com/crystal-lang/crystal/pull/10990), [#10988](https://github.com/crystal-lang/crystal/pull/10988), thanks @straight-shoota) - Allow constants and instance / class variables as receivers for setter proc pointers ([#10741](https://github.com/crystal-lang/crystal/pull/10741), thanks @HertzDevil) - Do not use globals for regex ([#10951](https://github.com/crystal-lang/crystal/pull/10951), thanks @asterite) - Define type filtering through an intersection operation ([#10781](https://github.com/crystal-lang/crystal/pull/10781), thanks @HertzDevil) - Fix no overflow check when primitive int converts to same type ([#11003](https://github.com/crystal-lang/crystal/pull/11003), thanks @HertzDevil) - Attach debug locations to generated internal LLVM functions ([#10934](https://github.com/crystal-lang/crystal/pull/10934), thanks @HertzDevil) - Add helpful error message for invalid number literal like '.42' ([#4665](https://github.com/crystal-lang/crystal/pull/4665), thanks @MakeNowJust) - Add `CrystalPath.expand_paths`, expand relative to compiler path ([#11030](https://github.com/crystal-lang/crystal/pull/11030), thanks @straight-shoota) - Clarify usage of "arguments" and "parameters" in error messages ([#10378](https://github.com/crystal-lang/crystal/pull/10378), thanks @HertzDevil) - **(performance)** Don't generate type IDs for formal generic instances ([#11167](https://github.com/crystal-lang/crystal/pull/11167), thanks @HertzDevil) - **(performance)** Don't generate unique type IDs for virtual metaclasses ([#11188](https://github.com/crystal-lang/crystal/pull/11188), thanks @HertzDevil) - Add an environment variable for dumping type IDs ([#11168](https://github.com/crystal-lang/crystal/pull/11168), thanks @HertzDevil) - Allow underscores in macro `for`'s loop variables ([#11141](https://github.com/crystal-lang/crystal/pull/11141), thanks @HertzDevil) - **(performance)** Compiler: cache cleanup transformer ([#11197](https://github.com/crystal-lang/crystal/pull/11197), thanks @asterite) - Avoid needless union in `LLVM::ABI::AArch64#homogeneous_aggregate?` ([#11199](https://github.com/crystal-lang/crystal/pull/11199), thanks @asterite) - Removing ThinLTO support ([#11194](https://github.com/crystal-lang/crystal/pull/11194), thanks @beta-ziliani) - Error if abstract def implementation is inherited from supertype ([#11056](https://github.com/crystal-lang/crystal/pull/11056), thanks @straight-shoota) - **(performance)** Add `inject_primitives: false` to macro_spec ([#11269](https://github.com/crystal-lang/crystal/pull/11269), thanks @straight-shoota) - Primitive annotations for interpreter ([#11147](https://github.com/crystal-lang/crystal/pull/11147), thanks @asterite) - Support generic module instances in `TypeNode#includers` ([#11116](https://github.com/crystal-lang/crystal/pull/11116), thanks @HertzDevil) - Reject hash literals with mixed syntax ([#11154](https://github.com/crystal-lang/crystal/pull/11154), thanks @MakeNowJust) ### Language - Make `.as?(NoReturn)` always return `nil` ([#10896](https://github.com/crystal-lang/crystal/pull/10896), thanks @HertzDevil) - Compiler: make `is_a?(union)` work correctly for virtual types ([#11176](https://github.com/crystal-lang/crystal/pull/11176), thanks @asterite) - Adjust docs for `Crystal::Macros::HashLiteral#[]` ([#10930](https://github.com/crystal-lang/crystal/pull/10930), thanks @kevinsjoberg) - Fix path lookup when ancestor finds type with same name as current scope ([#10901](https://github.com/crystal-lang/crystal/pull/10901), thanks @HertzDevil) - Fix several compile-time operations on generic instance metaclasses ([#11101](https://github.com/crystal-lang/crystal/pull/11101), thanks @HertzDevil) - Make `#is_a?` in macros respect the AST node hierarchy ([#11062](https://github.com/crystal-lang/crystal/pull/11062), thanks @HertzDevil) - Add docs to string methods in `SymbolLiteral` and `MacroId` ([#9298](https://github.com/crystal-lang/crystal/pull/9298), thanks @MakeNowJust) - Add clarification about when `instance_vars` can be called ([#11171](https://github.com/crystal-lang/crystal/pull/11171), thanks @willhbr) - Add `file_exists?` macro method ([#10540](https://github.com/crystal-lang/crystal/pull/10540), thanks @Sija) ### Standard Library - **(breaking-change)** Change nonsense return types to Nil: uncategorized ([#10625](https://github.com/crystal-lang/crystal/pull/10625), thanks @oprypin) - **(breaking-change)** Change nonsense return types to Nil in formatter classes ([#10623](https://github.com/crystal-lang/crystal/pull/10623), thanks @oprypin) - Add base64 to prelude ([#11050](https://github.com/crystal-lang/crystal/pull/11050), thanks @straight-shoota) - Remove calls to deprecated `SystemError.from_winerror` ([#11220](https://github.com/crystal-lang/crystal/pull/11220), thanks @straight-shoota) - Add support for LLVM 12 ([#10873](https://github.com/crystal-lang/crystal/pull/10873), [#11178](https://github.com/crystal-lang/crystal/pull/11178), thanks @maxfierke, @Blacksmoke16) - Examples: fix (2021-09) ([#11234](https://github.com/crystal-lang/crystal/pull/11234), thanks @maiha) - Don't use `:nodoc:` when overriding public methods ([#11096](https://github.com/crystal-lang/crystal/pull/11096), thanks @HertzDevil) - Add internal registry implementation for win32 ([#11137](https://github.com/crystal-lang/crystal/pull/11137), thanks @straight-shoota) #### Collection - **(breaking-change)** Move `Array#product` to `Indexable#cartesian_product` ([#10013](https://github.com/crystal-lang/crystal/pull/10013), thanks @HertzDevil) - Disallow `Slice(T).new(Int)` where `T` is a union of primitive number types ([#10982](https://github.com/crystal-lang/crystal/pull/10982), thanks @HertzDevil) - Make `Array#transpose`, `Enumerable#reject`, `Enumerable#to_h` work with tuples ([#10445](https://github.com/crystal-lang/crystal/pull/10445), thanks @HertzDevil) - Fix `Enumerable#each` block return type ([#10928](https://github.com/crystal-lang/crystal/pull/10928), thanks @straight-shoota) - Fix key type for empty `NamedTuple` be `Symbol` ([#10942](https://github.com/crystal-lang/crystal/pull/10942), thanks @caspiano) - Fix overflow in `BitArray#[](Int, Int)` for sizes between 33 and 64 ([#10809](https://github.com/crystal-lang/crystal/pull/10809), thanks @HertzDevil) - Fix `Range#step` for non-integer `Steppable` types ([#11130](https://github.com/crystal-lang/crystal/pull/11130), thanks @straight-shoota) - **(performance)** Construct an array literal in `NamedTuple#map` ([#10950](https://github.com/crystal-lang/crystal/pull/10950), thanks @caspiano) - Add `Slice#fill` ([#10924](https://github.com/crystal-lang/crystal/pull/10924), thanks @HertzDevil) - Add range overloads for `BitArray#toggle` ([#10743](https://github.com/crystal-lang/crystal/pull/10743), thanks @HertzDevil) - Add stable sort implementation to `Slice`, `Array` and `Indexable::Mutable` ([#10163](https://github.com/crystal-lang/crystal/pull/10163), [#11029](https://github.com/crystal-lang/crystal/pull/11029), [#11254](https://github.com/crystal-lang/crystal/pull/11254), thanks @MakeNowJust, thanks @straight-shoota) - Allow `Enumerable(T)#reduce`'s return type to differ from `T` ([#11065](https://github.com/crystal-lang/crystal/pull/11065), thanks @HertzDevil) - Implement `Enumerable#tally_by` ([#10922](https://github.com/crystal-lang/crystal/pull/10922), thanks @caspiano) - Add the `Indexable::Mutable(T)` module ([#11059](https://github.com/crystal-lang/crystal/pull/11059), thanks @HertzDevil) - Remove restriction of bsearch block output type ([#11212](https://github.com/crystal-lang/crystal/pull/11212), thanks @straight-shoota) - Add and improve type restrictions of block arguments ([#10467](https://github.com/crystal-lang/crystal/pull/10467), [#11246](https://github.com/crystal-lang/crystal/pull/11246), [#11267](https://github.com/crystal-lang/crystal/pull/11267, [#11308](https://github.com/crystal-lang/crystal/pull/11308), thanks @caspiano, thanks @straight-shoota, thanks @HertzDevil, thanks @beta-ziliani, thanks @caspiano) - **(performance)** Optimize `#rotate!` ([#11198](https://github.com/crystal-lang/crystal/pull/11198), thanks @HertzDevil) #### Concurrency - Fix Documentation of `Fiber.timeout` ([#11271](https://github.com/crystal-lang/crystal/pull/11271), thanks @toddsundsted) - **(performance)** `Scheduler#reschedule`: Shortcut lookup for current fiber. ([#11156](https://github.com/crystal-lang/crystal/pull/11156), thanks @yxhuvud) - Add sleep support to win32 event loop ([#10605](https://github.com/crystal-lang/crystal/pull/10605), thanks @straight-shoota) #### Files - **(breaking-change)** Change nonsense return types to Nil in IO-related methods ([#10621](https://github.com/crystal-lang/crystal/pull/10621), thanks @oprypin) - Fix `File.match?` to accept `Path` type as `path` argument ([#11075](https://github.com/crystal-lang/crystal/pull/11075), thanks @fishnibble) - Add `FileUtils` method specs with `String` and `Path` arguments ([#10987](https://github.com/crystal-lang/crystal/pull/10987), thanks @straight-shoota) - Make `IO#read_char`'s default behaviour UTF-8-strict ([#10446](https://github.com/crystal-lang/crystal/pull/10446), thanks @HertzDevil) - Fix glob with multiple recurse patterns ([#10813](https://github.com/crystal-lang/crystal/pull/10813), thanks @straight-shoota) - IO: fix bug in `gets` without peek involving `\r` and limit ([#11241](https://github.com/crystal-lang/crystal/pull/11241), thanks @asterite) - Make `FileUtils.mv` work across filesystems ([#10783](https://github.com/crystal-lang/crystal/pull/10783), thanks @naqvis) - **(performance)** Improve performance of `Path#dirname` and `Path#extension` ([#11001](https://github.com/crystal-lang/crystal/pull/11001), thanks @BlobCodes) #### Networking - **(breaking-change)** Change nonsense return types to `Nil` in HTTP-related methods and `Log` ([#10624](https://github.com/crystal-lang/crystal/pull/10624), thanks @oprypin) - Fix trailing `rescue` syntax ([#11083](https://github.com/crystal-lang/crystal/pull/11083), thanks @straight-shoota) - Fix spec for `HTTP::Params` can't run on its own ([#11128](https://github.com/crystal-lang/crystal/pull/11128), thanks @asterite) - Fix parsing cookie `Domain` attribute with leading dot ([#11098](https://github.com/crystal-lang/crystal/pull/11098), thanks @mamantoha) - Rescue `OpenSSL::SSL::Error` in `HTTP::Server#handle_client` ([#11146](https://github.com/crystal-lang/crystal/pull/11146), thanks @straight-shoota) - Fix `TCPSocket` constructors ([#11049](https://github.com/crystal-lang/crystal/pull/11049), thanks @straight-shoota) - Support basic auth from `URI` in websockets ([#10854](https://github.com/crystal-lang/crystal/pull/10854), thanks @willhbr) - Tag std specs that need network access ([#11048](https://github.com/crystal-lang/crystal/pull/11048), thanks @toshokan) - Proper handling of `max-age` and `expires` for cookies ([#10564](https://github.com/crystal-lang/crystal/pull/10564), thanks @straight-shoota, @watzon) - Retry `HTTP::Client` requests once if io is closed ([#11088](https://github.com/crystal-lang/crystal/pull/11088), thanks @carlhoerberg) - Implement `Socket` for win32 ([#10784](https://github.com/crystal-lang/crystal/pull/10784), thanks @straight-shoota) - Add `URI.encode_path` and deprecate `URI.encode` ([#11248](https://github.com/crystal-lang/crystal/pull/11248), thanks @straight-shoota) #### Numeric - **(breaking-change)** Refine type restriction of `Math.frexp(BigFloat)` ([#10998](https://github.com/crystal-lang/crystal/pull/10998), thanks @straight-shoota) - Fix `BigInt#to_s` emitting null bytes for certain values ([#11063](https://github.com/crystal-lang/crystal/pull/11063), thanks @HertzDevil) - Fix `Float#humanize` for values outside `1e-4...1e15` ([#10881](https://github.com/crystal-lang/crystal/pull/10881), thanks @straight-shoota) - Add type restrictions and fix return types of `BigFloat#to_x` methods ([#10996](https://github.com/crystal-lang/crystal/pull/10996), thanks @straight-shoota) - Add integer square root ([#10549](https://github.com/crystal-lang/crystal/pull/10549), thanks @kimburgess) - Add negative exponential support to BigDecimal ([#10892](https://github.com/crystal-lang/crystal/pull/10892), thanks @stakach) - Add `#next_float` and `#prev_float` to `Float32` and `Float64` ([#10908](https://github.com/crystal-lang/crystal/pull/10908), thanks @HertzDevil) - Add precision parameter to `Int#to_s` ([#10926](https://github.com/crystal-lang/crystal/pull/10926), thanks @HertzDevil) - **(performance)** Improve Int parsing performance ([#11093](https://github.com/crystal-lang/crystal/pull/11093), thanks @BlobCodes) - Implement `Int128` compiler-rt methods ([#11206](https://github.com/crystal-lang/crystal/pull/11206), thanks @BlobCodes) - Fix `BigDecimal` operations with floats ([#10874](https://github.com/crystal-lang/crystal/pull/10874), thanks @stakach) - Add `String#to_(u/i)128(?)` methods ([#11245](https://github.com/crystal-lang/crystal/pull/11245), thanks @BlobCodes) #### Runtime - Extract `libunwind` from callstack ([#11205](https://github.com/crystal-lang/crystal/pull/11205), thanks @straight-shoota) #### Serialization - **(breaking-change)** Change nonsense return types to `Nil`: JSON and YAML ([#10622](https://github.com/crystal-lang/crystal/pull/10622), thanks @oprypin) - **(breaking-change)** Add type restriction and conversion to `YAML::PullParser#location` ([#10997](https://github.com/crystal-lang/crystal/pull/10997), thanks @straight-shoota) - Allow EOF IO passed to `JSON::PullParser.new` ([#10864](https://github.com/crystal-lang/crystal/pull/10864), thanks @Blacksmoke16) - Quote the named tuple's keys on deserialization ([#10919](https://github.com/crystal-lang/crystal/pull/10919), thanks @Blacksmoke16) - Refactor `JSON::PullParser#consume_number` to use stdlib number parsing ([#10447](https://github.com/crystal-lang/crystal/pull/10447), thanks @straight-shoota) - XML Namespace improvements ([#11072](https://github.com/crystal-lang/crystal/pull/11072), thanks @Blacksmoke16) - Add JSON/YAML serialization to `URI` ([#10404](https://github.com/crystal-lang/crystal/pull/10404), thanks @straight-shoota) #### Specs - Add missing require in `iterator_spec` ([#11148](https://github.com/crystal-lang/crystal/pull/11148), thanks @asterite) - Add missing requires to run a couple of specs standalone ([#11152](https://github.com/crystal-lang/crystal/pull/11152), thanks @asterite) - Allow `describe` without requiring an argument ([#10974](https://github.com/crystal-lang/crystal/pull/10974), thanks @straight-shoota) #### System - SystemError: Fix inconsistent signature. ([#11002](https://github.com/crystal-lang/crystal/pull/11002), thanks @yxhuvud) #### Text - **(breaking-change)** Deprecate `String#unsafe_byte_at` ([#10559](https://github.com/crystal-lang/crystal/pull/10559), thanks @straight-shoota) - **(breaking-change)** Rename `IO#write_utf8` to `#write_string`. ([#11051](https://github.com/crystal-lang/crystal/pull/11051), thanks @straight-shoota) - Use `#write_string` instead of `#write` whenever writing strings to unknown `IO`s ([#11011](https://github.com/crystal-lang/crystal/pull/11011), thanks @HertzDevil) - Don't use `#write_byte` whenever writing ASCII characters to unknown `IO`s ([#11124](https://github.com/crystal-lang/crystal/pull/11124), thanks @HertzDevil) - Make `Int#chr` reject surrogate halves ([#10451](https://github.com/crystal-lang/crystal/pull/10451), thanks @HertzDevil) - CSV: don't eagerly check next char after newline ([#11174](https://github.com/crystal-lang/crystal/pull/11174), thanks @asterite) - Fix link on regex.cr ([#11204](https://github.com/crystal-lang/crystal/pull/11204), thanks @gemmaro) - Disallow non-UTF-8 encoding settings for `String::Builder` ([#11025](https://github.com/crystal-lang/crystal/pull/11025), thanks @HertzDevil) - Unicode: update to version 14.0.0 ([#11215](https://github.com/crystal-lang/crystal/pull/11215), thanks @Blacksmoke16) ### Tools - Formatter: Handle `(-> )` correctly ([#10945](https://github.com/crystal-lang/crystal/pull/10945), thanks @HertzDevil) - Use [markd](https://github.com/icyleaf/markd) for markdown rendering in the compiler ([#11040](https://github.com/crystal-lang/crystal/pull/11040), thanks @straight-shoota) - Formatter: Handle leading tuple literals in multi-expression `return`/`break`/`next` properly ([#10597](https://github.com/crystal-lang/crystal/pull/10597), thanks @HertzDevil) - Include parent headings in anchor links ([#9839](https://github.com/crystal-lang/crystal/pull/9839), thanks @Blacksmoke16) - Fix formatting nested multiline array and tuple ([#11153](https://github.com/crystal-lang/crystal/pull/11153), thanks @MakeNowJust) - `crystal init`: Improve transformation of project name with hyphens ([#11170](https://github.com/crystal-lang/crystal/pull/11170), thanks @Kanezoh) - Fix formatting generic types with suffix ([#11187](https://github.com/crystal-lang/crystal/pull/11187), thanks @MakeNowJust) - Make `WARNING` an admonition keyword ([#10898](https://github.com/crystal-lang/crystal/pull/10898), thanks @HertzDevil) - Refactor hierarchy printers ([#10791](https://github.com/crystal-lang/crystal/pull/10791), thanks @HertzDevil) ### Other - Fix typos ([#11045](https://github.com/crystal-lang/crystal/pull/11045), [#11163](https://github.com/crystal-lang/crystal/pull/11163), [#11138](https://github.com/crystal-lang/crystal/pull/11138), hanks @toshokan, thanks @MakeNowJust, thanks @schmijos) - Update readme to point to IRC channel on libera.chat ([#11024](https://github.com/crystal-lang/crystal/pull/11024), thanks @jhass) - [CI] Update ruby-install ([#11276](https://github.com/crystal-lang/crystal/pull/11276), thanks @straight-shoota) - [CI] Remove `test_linux_32` and add smoke test for 32-bit gnu ([#11127](https://github.com/crystal-lang/crystal/pull/11127), thanks @straight-shoota) - [CI] Remove obsolete `package_build` workflow ([#11240](https://github.com/crystal-lang/crystal/pull/11240), thanks @straight-shoota) - [CI] Add build matrix with 1.0.0 and 1.1.1 ([#11278](https://github.com/crystal-lang/crystal/pull/11278), thanks @straight-shoota) - [CI] Update aarch64.yml ([#11160](https://github.com/crystal-lang/crystal/pull/11160), thanks @beta-ziliani) - [CI] Update distribution-scripts (universal darwin & demote alpine to 3.12) ([#11228](https://github.com/crystal-lang/crystal/pull/11228), thanks @bcardiff) - Update shards 0.16.0 ([#11292](https://github.com/crystal-lang/crystal/pull/11292), thanks @straight-shoota) - Update previous release Crystal 1.1.0 ([#10955](https://github.com/crystal-lang/crystal/pull/10955), thanks @straight-shoota) - Merge changelog entry for 1.1.1 ([#11028](https://github.com/crystal-lang/crystal/pull/11028), thanks @straight-shoota) - Update previous release Crystal 1.1.1 ([#11053](https://github.com/crystal-lang/crystal/pull/11053), thanks @straight-shoota) - PR template ([#10894](https://github.com/crystal-lang/crystal/pull/10894), thanks @beta-ziliani) - Add github-changelog script ([#11155](https://github.com/crystal-lang/crystal/pull/11155), thanks @straight-shoota) - Add `make install` ([#10878](https://github.com/crystal-lang/crystal/pull/10878), thanks @straight-shoota) - [CI] Sanitize version from branch name ([#11294](https://github.com/crystal-lang/crystal/pull/11294), thanks @straight-shoota) - Update libgc to 8.2.0 ([#11293](https://github.com/crystal-lang/crystal/pull/11293), thanks @straight-shoota) - [CI] Unify `maintenance_release` and `tagged_release` workflows ([#11273](https://github.com/crystal-lang/crystal/pull/11273), thanks @straight-shoota) - [CI] Update distribution-scripts (make install) ([#11307](https://github.com/crystal-lang/crystal/pull/11307), thanks @straight-shoota) - [CI] Enable publish docker images on tagged release ([#11309](https://github.com/crystal-lang/crystal/pull/11309), thanks @straight-shoota) - [CI] Update distribution-scripts (fix for libgc in alpine Docker image) ([#11310](https://github.com/crystal-lang/crystal/pull/11310), thanks @straight-shoota) - [CI] Pin macOS runner to 10.15 ([#11282](https://github.com/crystal-lang/crystal/pull/11282), thanks @straight-shoota) - [CI] Fix `push_obs_nightly` ([#11301](https://github.com/crystal-lang/crystal/pull/11301), thanks @straight-shoota) - [CI] Update distribution-scripts ([#11285](https://github.com/crystal-lang/crystal/pull/11285), thanks @straight-shoota) - [CI] Remove i386 builds ([#11287](https://github.com/crystal-lang/crystal/pull/11287), thanks @straight-shoota) ================================================ FILE: doc/changelogs/v1.3.md ================================================ # Changelog 1.3 ## [1.3.2] - 2022-01-18 [1.3.2]: https://github.com/crystal-lang/crystal/releases/1.3.2 ### Standard Library #### Text - Fix buffer overflow in `String#index` ([#11747](https://github.com/crystal-lang/crystal/pull/11747), thanks @asterite, @straight-shoota) ## [1.3.1] - 2022-01-13 [1.3.1]: https://github.com/crystal-lang/crystal/releases/1.3.1 ### Standard Library - Remove useless variable declarations in trailing position ([#11704](https://github.com/crystal-lang/crystal/pull/11704), thanks @HertzDevil) #### Crypto - Fix for missing `BIO_*` functions in OpenSSL < 1.1.0 ([#11736](https://github.com/crystal-lang/crystal/pull/11736), thanks @daliborfilus) #### Runtime - Remove string allocation from `GC_set_warn_proc` ([#11729](https://github.com/crystal-lang/crystal/pull/11729), thanks @straight-shoota) ### Tools - Doc generator: Fix escape HTML in code span ([#11686](https://github.com/crystal-lang/crystal/pull/11686), thanks @straight-shoota) - Fix formatter error for `ProcLiteral`s with `Union` return type ([#11709](https://github.com/crystal-lang/crystal/pull/11709), thanks @HertzDevil) ### Other - Fix typos ([#11725](https://github.com/crystal-lang/crystal/pull/11725), thanks @kianmeng) ## [1.3.0] - 2022-01-06 [1.3.0]: https://github.com/crystal-lang/crystal/releases/1.3.0 ### Compiler - Refer to `T.class` as "metaclass" in error messages, not "class" ([#11378](https://github.com/crystal-lang/crystal/pull/11378), thanks @HertzDevil) - Create `Reason` enum for exhaustive case in nil-reason check ([#11449](https://github.com/crystal-lang/crystal/pull/11449), thanks @rymiel) - Improve cache directory behaviour on Windows ([#11436](https://github.com/crystal-lang/crystal/pull/11436), thanks @HertzDevil) - Automatically detect MSVC tools on Windows via `vswhere` ([#11496](https://github.com/crystal-lang/crystal/pull/11496), thanks @HertzDevil) - Clean up .pdb files for temporary executables on MSVC ([#11553](https://github.com/crystal-lang/crystal/pull/11553), thanks @HertzDevil) - Disable incremental linking on MSVC ([#11552](https://github.com/crystal-lang/crystal/pull/11552), thanks @HertzDevil) - Allow multiple `--emit` compiler options to stack ([#11556](https://github.com/crystal-lang/crystal/pull/11556), thanks @HertzDevil) - Refactor some type restrictions in the compiler ([#11531](https://github.com/crystal-lang/crystal/pull/11531), thanks @straight-shoota) - Detect `cl.exe`'s path for compiler specs requiring a C compiler ([#11560](https://github.com/crystal-lang/crystal/pull/11560), thanks @HertzDevil) - Increase default stack size on MSVC to 8 MB ([#11569](https://github.com/crystal-lang/crystal/pull/11569), thanks @HertzDevil) - Resolve compiler wildcard require ([#11562](https://github.com/crystal-lang/crystal/pull/11562), thanks @straight-shoota) - Compiler: use enums instead of symbols in various places ([#11607](https://github.com/crystal-lang/crystal/pull/11607), thanks @HertzDevil) #### Codegen - Disable specs for `StaticArray#sort_by` on broken targets ([#11359](https://github.com/crystal-lang/crystal/pull/11359), thanks @straight-shoota) - Fix link flag behaviour on Windows MSVC ([#11424](https://github.com/crystal-lang/crystal/pull/11424), thanks @HertzDevil) - Attach debug locations to splat expansions inside array-like literals ([#11655](https://github.com/crystal-lang/crystal/pull/11655), thanks @HertzDevil) - Use full name for private types' class variables during codegen ([#11651](https://github.com/crystal-lang/crystal/pull/11651), thanks @HertzDevil) - Fix codegen when instantiating class methods of typedefs ([#11636](https://github.com/crystal-lang/crystal/pull/11636), thanks @HertzDevil) - Add minimal load-time DLL support on Windows, support `dllimport` storage class ([#11573](https://github.com/crystal-lang/crystal/pull/11573), thanks @HertzDevil) #### Debugger - Attach debug locations to auto-generated `initialize` methods ([#11313](https://github.com/crystal-lang/crystal/pull/11313), thanks @HertzDevil) - Fix debug location for `~check_proc_is_not_closure` ([#11311](https://github.com/crystal-lang/crystal/pull/11311), thanks @HertzDevil) #### Interpreter - `crystal i`, a Crystal interpreter ([#11159](https://github.com/crystal-lang/crystal/pull/11159), thanks @asterite) - Implement FFI bindings ([#11475](https://github.com/crystal-lang/crystal/pull/11475), thanks @straight-shoota) - Add `Crystal::Loader` ([#11434](https://github.com/crystal-lang/crystal/pull/11434), [#11662](https://github.com/crystal-lang/crystal/pull/11662), thanks @straight-shoota, @HertzDevil) - Mark `bswap32` intrinsic with interpreter primitive annotation ([#11582](https://github.com/crystal-lang/crystal/pull/11582), thanks @rymiel) - Split interpreter specs into separate files ([#11578](https://github.com/crystal-lang/crystal/pull/11578), thanks @straight-shoota) - Workaround for GC issues in interpreter specs ([#11634](https://github.com/crystal-lang/crystal/pull/11634), thanks @straight-shoota) #### Parser - Parser: allow keyword as named argument inside macros ([#10377](https://github.com/crystal-lang/crystal/pull/10377), thanks @asterite) - Parser: add missing end location to `IsA` node ([#11351](https://github.com/crystal-lang/crystal/pull/11351), thanks @FnControlOption) - Fix node locations for `ProcLiteral`s with parameters ([#11365](https://github.com/crystal-lang/crystal/pull/11365), thanks @HertzDevil) - Fix parser error with named argument `end` in macro body ([#11463](https://github.com/crystal-lang/crystal/pull/11463), thanks @straight-shoota) - Report syntax error for too-long bin/hex/oct integer literals ([#11447](https://github.com/crystal-lang/crystal/pull/11447), thanks @oprypin) - [lexer] Correctly increase nesting for escaped macro `unless` ([#11440](https://github.com/crystal-lang/crystal/pull/11440), thanks @rymiel) - Show proper syntax errors in some edge cases in the parser ([#11446](https://github.com/crystal-lang/crystal/pull/11446), thanks @oprypin) - Fix parse `yield` with parenthesis ([#11469](https://github.com/crystal-lang/crystal/pull/11469), thanks @straight-shoota) - Lexer number parsing refactor ([#11211](https://github.com/crystal-lang/crystal/pull/11211), thanks @BlobCodes) - Allow underscores after a leading zero in `String#to_i` (regression fix) ([#11672](https://github.com/crystal-lang/crystal/pull/11672), thanks @BlobCodes) - Fix no comma before short block in `ToSVisitor` ([#11677](https://github.com/crystal-lang/crystal/pull/11677), thanks @homonoidian) - Unify format of "unexpected token" error ([#11473](https://github.com/crystal-lang/crystal/pull/11473), thanks @straight-shoota) - Implement lexer int128 support ([#11571](https://github.com/crystal-lang/crystal/pull/11571), thanks @BlobCodes) #### Semantic - Show proper owner for `Class`'s methods in error messages ([#10590](https://github.com/crystal-lang/crystal/pull/10590), thanks @HertzDevil) - Be more strict about `ProcNotation` variable declarations ([#11372](https://github.com/crystal-lang/crystal/pull/11372), thanks @HertzDevil) - Allow metaclass parameters in `Proc` literals and pointers ([#11367](https://github.com/crystal-lang/crystal/pull/11367), thanks @HertzDevil) - Fix top-level multi-assign splat variable not working in macros ([#11600](https://github.com/crystal-lang/crystal/pull/11600), thanks @HertzDevil) - Replace `semantic` with `assert_no_errors` in compiler specs whenever possible ([#11288](https://github.com/crystal-lang/crystal/pull/11288), thanks @HertzDevil) - Make `inject_primitives = false` default for semantic specs ([#11297](https://github.com/crystal-lang/crystal/pull/11297), thanks @HertzDevil) - Add spec for #8428 ([#10073](https://github.com/crystal-lang/crystal/pull/10073), thanks @docelic) - Remove and resolve spurious cast and its associated FIXME ([#11455](https://github.com/crystal-lang/crystal/pull/11455), thanks @rymiel) - Add pending spec for recursive abstract struct ([#11470](https://github.com/crystal-lang/crystal/pull/11470), thanks @HertzDevil) ### Language - **(breaking-change)** Require elements in 1-to-n assignments to match targets exactly ([#11145](https://github.com/crystal-lang/crystal/pull/11145), thanks @HertzDevil) - **(breaking-change)** Require right-hand side of one-to-many assignments to be `Indexable` ([#11545](https://github.com/crystal-lang/crystal/pull/11545), thanks @HertzDevil) - Support splats on left-hand sides of multiple assignment expressions ([#10410](https://github.com/crystal-lang/crystal/pull/10410), thanks @HertzDevil) - Make all AST nodes immutable through container-returning methods ([#11397](https://github.com/crystal-lang/crystal/pull/11397), thanks @HertzDevil) - Add auto upcast for integer and float values ([#11431](https://github.com/crystal-lang/crystal/pull/11431), [#11529](https://github.com/crystal-lang/crystal/pull/11529), thanks @asterite, @beta-ziliani) ### Standard Library - Fix `Process::INITIAL_PWD` for non-existent path ([#10525](https://github.com/crystal-lang/crystal/pull/10525), thanks @straight-shoota) - Resolve some TODOs ([#11369](https://github.com/crystal-lang/crystal/pull/11369), thanks @straight-shoota) - Refactor some target flag uses ([#11466](https://github.com/crystal-lang/crystal/pull/11466), thanks @straight-shoota) - Use `Slice(UInt8)#fill` in the standard library ([#11468](https://github.com/crystal-lang/crystal/pull/11468), thanks @HertzDevil) - Update `spec/win32_std_spec.cr` ([#11432](https://github.com/crystal-lang/crystal/pull/11432), [#11637](https://github.com/crystal-lang/crystal/pull/11637), thanks @HertzDevil) - Use strings instead of symbols in `#finalize` specs ([#11619](https://github.com/crystal-lang/crystal/pull/11619), thanks @HertzDevil) - Fix `Enum.parse` to handle case-sensitive member names ([#11659](https://github.com/crystal-lang/crystal/pull/11659), thanks @straight-shoota) - Improve docs for `Object#not_nil!` ([#11661](https://github.com/crystal-lang/crystal/pull/11661), thanks @straight-shoota) #### Collection - **(breaking-change)** Always use `start` as parameter in subrange-accepting methods ([#11350](https://github.com/crystal-lang/crystal/pull/11350), thanks @HertzDevil) - **(breaking-change)** Refactor `Indexable::Mutable#fill`'s overloads ([#11368](https://github.com/crystal-lang/crystal/pull/11368), thanks @HertzDevil) - Add sorting methods to `StaticArray` ([#10889](https://github.com/crystal-lang/crystal/pull/10889), thanks @HertzDevil) - Add spaceship operator to `StaticArray` ([#11364](https://github.com/crystal-lang/crystal/pull/11364), thanks @henrikac) - **(performance)** Optimize `BitArray#reverse!` ([#11363](https://github.com/crystal-lang/crystal/pull/11363), thanks @HertzDevil) - **(performance)** Grow large arrays more slowly ([#11482](https://github.com/crystal-lang/crystal/pull/11482), thanks @mgomes) - Fix docs for `Indexable::Mutable#map!` ([#11349](https://github.com/crystal-lang/crystal/pull/11349), thanks @HertzDevil) - Add `Slice#unsafe_slice_of`, `#to_unsafe_bytes` ([#11379](https://github.com/crystal-lang/crystal/pull/11379), thanks @HertzDevil) - **(performance)** Avoid reallocation in `Enumerable#each_cons` and `Iterator#cons`'s default reused array ([#10384](https://github.com/crystal-lang/crystal/pull/10384), thanks @HertzDevil) - Fix `Array#unshift` for large arrays ([#11656](https://github.com/crystal-lang/crystal/pull/11656), thanks @HertzDevil) #### Crypto - Support OpenSSL on Windows ([#11477](https://github.com/crystal-lang/crystal/pull/11477), thanks @HertzDevil) - Encode OpenSSL version on Windows ([#11516](https://github.com/crystal-lang/crystal/pull/11516), thanks @HertzDevil) - Add docs to `Crypto::Bcrypt` ([#9647](https://github.com/crystal-lang/crystal/pull/9647), thanks @j8r) - Fix `getrandom` for interpreter ([#11624](https://github.com/crystal-lang/crystal/pull/11624), thanks @straight-shoota) - **(performance)** Use more efficient method to split `UInt32` to bytes in `Crypto::Blowfish` ([#11594](https://github.com/crystal-lang/crystal/pull/11594), thanks @BlobCodes) #### Files - Add bindings to `__xstat`, `__fxstat` and `__lxstat` for x86_64-linux-gnu ([#11361](https://github.com/crystal-lang/crystal/pull/11361), [#11536](https://github.com/crystal-lang/crystal/pull/11536), thanks @straight-shoota) - Fix `IO::Memory#to_s` appending to itself ([#11643](https://github.com/crystal-lang/crystal/pull/11643), thanks @straight-shoota) #### LLVM - Fix `LLVMExtDIBuilderCreateArrayType` argument `alignInBits` should be `UInt64` ([#11644](https://github.com/crystal-lang/crystal/pull/11644), thanks @lbguilherme) #### Log - Add `Log.with_context` with kwargs ([#11517](https://github.com/crystal-lang/crystal/pull/11517), thanks @caspiano) - Refactor `Log::BroadcastBackend#single_backend?` ([#11530](https://github.com/crystal-lang/crystal/pull/11530), thanks @straight-shoota) #### Macros - Add macro methods for `Return`, `Break`, `Next`, `Yield`, and exception handlers ([#10822](https://github.com/crystal-lang/crystal/pull/10822), thanks @HertzDevil) - Add `Crystal::Macros::ProcNotation#resolve` and `#resolve?` ([#11373](https://github.com/crystal-lang/crystal/pull/11373), thanks @HertzDevil) - Support explicit return types in `ProcLiteral`s ([#11402](https://github.com/crystal-lang/crystal/pull/11402), thanks @HertzDevil) - Add several missing `ASTNode` macro methods ([#10811](https://github.com/crystal-lang/crystal/pull/10811), thanks @HertzDevil) - Allow incomplete range arguments for `#[](Range)` macro methods ([#11380](https://github.com/crystal-lang/crystal/pull/11380), thanks @HertzDevil) - Add macro methods for `Metaclass` nodes ([#11375](https://github.com/crystal-lang/crystal/pull/11375), thanks @HertzDevil) #### Networking - Datagram support for `UNIXServer` ([#11426](https://github.com/crystal-lang/crystal/pull/11426), thanks @carlhoerberg) - Fix `WebSocket#stream` flushing for not exactly buffer size, add specs ([#11299](https://github.com/crystal-lang/crystal/pull/11299), thanks @will) - Fix flag for UNIX-like OS ([#11382](https://github.com/crystal-lang/crystal/pull/11382), thanks @straight-shoota) - Add more `check_headers` to `HTTP::Server::Response` ([#11253](https://github.com/crystal-lang/crystal/pull/11253), thanks @straight-shoota) - Enable `LogHandler` address for win32 ([#11465](https://github.com/crystal-lang/crystal/pull/11465), thanks @straight-shoota) - Enable two specs to run on all platforms ([#11467](https://github.com/crystal-lang/crystal/pull/11467), thanks @straight-shoota) - `TCPServer`: explain how to get an ephemeral port ([#11407](https://github.com/crystal-lang/crystal/pull/11407), thanks @rdp) - Fix `HTTP::Server::Response#close` when replaced output syncs close ([#11631](https://github.com/crystal-lang/crystal/pull/11631), thanks @straight-shoota) #### Numeric - **(breaking-change)** Fix `Random.rand(max : Float32)` return `Float32` ([#9946](https://github.com/crystal-lang/crystal/pull/9946), thanks @j8r) - Fix `Math` linking errors on Windows MSVC ([#11435](https://github.com/crystal-lang/crystal/pull/11435), thanks @HertzDevil) - Implement compiler-rt `__multi3` for arm ([#11499](https://github.com/crystal-lang/crystal/pull/11499), thanks @straight-shoota) - Use MPIR for `Big*` numbers on Windows ([#11412](https://github.com/crystal-lang/crystal/pull/11412), thanks @HertzDevil) - Add `BigRational#to_big_r` ([#11462](https://github.com/crystal-lang/crystal/pull/11462), thanks @HertzDevil) - Move specs for arithmetic primitives to `primitives_spec` ([#11298](https://github.com/crystal-lang/crystal/pull/11298), thanks @HertzDevil) - Implement compiler-rt's 128-bit integer conversions to/from floats ([#11437](https://github.com/crystal-lang/crystal/pull/11437), thanks @HertzDevil) - Fix `Number.significant` to return `0` as is, not as `Float64` ([#11321](https://github.com/crystal-lang/crystal/pull/11321), thanks @Sija) - Fix inequality for floating-point NaNs ([#11229](https://github.com/crystal-lang/crystal/pull/11229), thanks @HertzDevil) - Add workaround for 128-bit integer division/modulo on Windows ([#11551](https://github.com/crystal-lang/crystal/pull/11551), thanks @HertzDevil) - Reject near-boundary and NaN values for `Float`-to-`Int` conversions ([#11230](https://github.com/crystal-lang/crystal/pull/11230), thanks @HertzDevil) #### Runtime - GC/Boehm: Silence GC warnings about big allocations. ([#11289](https://github.com/crystal-lang/crystal/pull/11289), thanks @yxhuvud) - Disable impossible spec on win32, previously marked as pending ([#11451](https://github.com/crystal-lang/crystal/pull/11451), thanks @straight-shoota) - Support call stacks on Windows ([#11461](https://github.com/crystal-lang/crystal/pull/11461), thanks @HertzDevil) - Make Windows PDB lookup relative to running executable ([#11493](https://github.com/crystal-lang/crystal/pull/11493), thanks @HertzDevil) #### Serialization - Parses JSON `UInt64` numbers. ([#11395](https://github.com/crystal-lang/crystal/pull/11395), thanks @hugopl) - Fix `YAML::Any` deserialize with alias ([#11532](https://github.com/crystal-lang/crystal/pull/11532), thanks @straight-shoota) #### Specs - Use enums instead of symbols for `Spec`-related types ([#11585](https://github.com/crystal-lang/crystal/pull/11585), thanks @HertzDevil) #### System - Add native Linux syscall interface ([#10777](https://github.com/crystal-lang/crystal/pull/10777), thanks @lbguilherme) - Implement `Path.home` on Windows ([#11503](https://github.com/crystal-lang/crystal/pull/11503), thanks @HertzDevil) - Support `~\` for Windows paths in `Path#expand` and `File.expand_path` ([#11559](https://github.com/crystal-lang/crystal/pull/11559), thanks @HertzDevil) - Support non-ASCII command-line arguments on Windows ([#11564](https://github.com/crystal-lang/crystal/pull/11564), thanks @HertzDevil) - Enable `kernel_spec.cr` on Windows CI ([#11554](https://github.com/crystal-lang/crystal/pull/11554), thanks @HertzDevil) - Fix `getrandom` syscall was blocking and didn't had proper error checking ([#11460](https://github.com/crystal-lang/crystal/pull/11460), thanks @lbguilherme) #### Text - Regex: use `PCRE_UCP` ([#11265](https://github.com/crystal-lang/crystal/pull/11265), thanks @asterite) - Add missing `it` in `UUID` spec ([#11353](https://github.com/crystal-lang/crystal/pull/11353), thanks @darkstego) - Add `Char#unicode_escape` and fix `#dump` and `#inspect` format ([#11421](https://github.com/crystal-lang/crystal/pull/11421), thanks @straight-shoota) - Fix `Char#letter?` to include all letter categories ([#11474](https://github.com/crystal-lang/crystal/pull/11474), thanks @straight-shoota) - Pass JIT Compile flag to `study` ([#11325](https://github.com/crystal-lang/crystal/pull/11325), thanks @Blacksmoke16) - Add Comparison operator to UUID ([#11352](https://github.com/crystal-lang/crystal/pull/11352), thanks @darkstego) - Add `Char#printable?` ([#11429](https://github.com/crystal-lang/crystal/pull/11429), thanks @straight-shoota) - Fix `String#inspect` and `Char#inspect` escape all non-printable characters ([#11452](https://github.com/crystal-lang/crystal/pull/11452), [#11626](https://github.com/crystal-lang/crystal/pull/11626), thanks @straight-shoota) - Support custom encodings on Windows through GNU libiconv ([#11480](https://github.com/crystal-lang/crystal/pull/11480), thanks @HertzDevil) - **(breaking-change)** Change `Regex#name_table` to return `Hash(Int32, String)` ([#11539](https://github.com/crystal-lang/crystal/pull/11539), thanks @straight-shoota) - Fix skip surrogates in `Char#succ` and `#pred` ([#11506](https://github.com/crystal-lang/crystal/pull/11506), thanks @straight-shoota) - **(performance)** Improve Base64 decoding performance ([#11094](https://github.com/crystal-lang/crystal/pull/11094), thanks @BlobCodes) - Refactor syntax highlighter and add ANSI escape code highlighter for console ([#11366](https://github.com/crystal-lang/crystal/pull/11366), thanks @straight-shoota) - Fix UTF-8 console input/output on Windows ([#11557](https://github.com/crystal-lang/crystal/pull/11557), thanks @HertzDevil) - Implement Unicode grapheme clusters ([#11472](https://github.com/crystal-lang/crystal/pull/11472), [#11611](https://github.com/crystal-lang/crystal/pull/11611), thanks @straight-shoota) - **(breaking-change)** Fix `Char#ascii_control?` restrict to ASCII characters ([#11510](https://github.com/crystal-lang/crystal/pull/11510), thanks @straight-shoota) - **(performance)** Performance: specify string sizes in advance ([#11592](https://github.com/crystal-lang/crystal/pull/11592), thanks @BlobCodes) - **(performance)** Improve performance of `Char#to_s` ([#11593](https://github.com/crystal-lang/crystal/pull/11593), thanks @BlobCodes) - Add docs to `Colorize` ([#11664](https://github.com/crystal-lang/crystal/pull/11664), thanks @straight-shoota) - Support ANSI escape sequence output on more Windows consoles ([#11622](https://github.com/crystal-lang/crystal/pull/11622), thanks @HertzDevil) ### Tools - [docs] Fix ditto with additional lines ([#11336](https://github.com/crystal-lang/crystal/pull/11336), thanks @straight-shoota) - [docs] Compact some JSON fields for search ([#11438](https://github.com/crystal-lang/crystal/pull/11438), thanks @rymiel) - [docs] Add 404.html page ([#11428](https://github.com/crystal-lang/crystal/pull/11428), thanks @straight-shoota) - [docs] Improve search input a11y for generated docs ([#11604](https://github.com/crystal-lang/crystal/pull/11604), thanks @chances) - [docs] use `shard.yml` version when no git tag present ([#11232](https://github.com/crystal-lang/crystal/pull/11232), thanks @superhawk610) - [formatter] Fix weird interactions with comments near indentation ([#11441](https://github.com/crystal-lang/crystal/pull/11441), thanks @rymiel) - [formatter] fix extra newline after comment in case else ([#11448](https://github.com/crystal-lang/crystal/pull/11448), thanks @rymiel) - [formatter] Fix space between call name and parenthesized arg ([#11523](https://github.com/crystal-lang/crystal/pull/11523), thanks @straight-shoota) - [playground] Refactor `PlaygroundPage` resources list ([#11608](https://github.com/crystal-lang/crystal/pull/11608), thanks @straight-shoota) ### Other - Update previous Crystal release - 1.2.2 ([#11430](https://github.com/crystal-lang/crystal/pull/11430), thanks @straight-shoota) - Prepare 1.3.0-dev ([#11317](https://github.com/crystal-lang/crystal/pull/11317), thanks @straight-shoota) - [CI] Fix `test_dist_linux_on_docker` ([#11512](https://github.com/crystal-lang/crystal/pull/11512), thanks @straight-shoota) - Improve compiler spec helpers for macro methods ([#11139](https://github.com/crystal-lang/crystal/pull/11139), thanks @HertzDevil) - Add Makefile to build samples ([#11419](https://github.com/crystal-lang/crystal/pull/11419), thanks @straight-shoota) - Verify downloads' hashes in Windows CI ([#11423](https://github.com/crystal-lang/crystal/pull/11423), thanks @matiasgarciaisaia) - Make the Windows compiler artifact more portable ([#11494](https://github.com/crystal-lang/crystal/pull/11494), thanks @HertzDevil) - Allow compiler executable under test to be overridden ([#11457](https://github.com/crystal-lang/crystal/pull/11457), thanks @HertzDevil) - Fix CI rules for building libiconv on Windows ([#11504](https://github.com/crystal-lang/crystal/pull/11504), thanks @HertzDevil) - Update license template ([#11498](https://github.com/crystal-lang/crystal/pull/11498), thanks @taupiqueur) - Pin alpine repo for ssl libs to 3.15 ([#11500](https://github.com/crystal-lang/crystal/pull/11500), thanks @straight-shoota) - Don't generate PDB for MPIR on Windows ([#11521](https://github.com/crystal-lang/crystal/pull/11521), thanks @HertzDevil) - [Makefile] Check for `LLVM_CONFIG` only when LLVM is used ([#11519](https://github.com/crystal-lang/crystal/pull/11519), thanks @straight-shoota) - Update distribution-scripts ([#11514](https://github.com/crystal-lang/crystal/pull/11514), [#11515](https://github.com/crystal-lang/crystal/pull/11515), thanks @straight-shoota) - Add commit hash to Windows builds ([#11538](https://github.com/crystal-lang/crystal/pull/11538), thanks @HertzDevil) - Support BuildTools and other VS variants in vswhere detection ([#11534](https://github.com/crystal-lang/crystal/pull/11534), thanks @neatorobito) - Define `LIBXML_STATIC` when building xml2.lib on Windows ([#11574](https://github.com/crystal-lang/crystal/pull/11574), thanks @HertzDevil) - Improve texts in `README.md` ([#11587](https://github.com/crystal-lang/crystal/pull/11587), thanks @athix) - Include `shards` with Windows build artifacts ([#11543](https://github.com/crystal-lang/crystal/pull/11543), thanks @neatorobito) - [CI] Remove `libatomic_ops` ([#11598](https://github.com/crystal-lang/crystal/pull/11598), thanks @straight-shoota) - Update NOTICE Copyright year to 2022 ([#11679](https://github.com/crystal-lang/crystal/pull/11679), thanks @matiasgarciaisaia) ================================================ FILE: doc/changelogs/v1.4.md ================================================ # Changelog 1.4 ## [1.4.1] - 2022-04-22 [1.4.1]: https://github.com/crystal-lang/crystal/releases/1.4.1 ### Standard Library #### Collection - Avoid compile-time error on empty `NamedTuple`s. ([#12007](https://github.com/crystal-lang/crystal/pull/12007), thanks @I3oris) #### Files - Add missing fun def for `__xstat` ([#11985](https://github.com/crystal-lang/crystal/pull/11985), thanks @straight-shoota) #### Runtime - Add `pthread` link annotations in lib bindings ([#12013](https://github.com/crystal-lang/crystal/pull/12013), thanks @straight-shoota) - Fix GC typedefs on Windows ([#11963](https://github.com/crystal-lang/crystal/pull/11963), thanks @HertzDevil) ### Compiler #### Semantic - Compiler: remove duplicate instance vars once we know them all ([#11995](https://github.com/crystal-lang/crystal/pull/11995), thanks @asterite) ## [1.4.0] - 2022-04-06 [1.4.0]: https://github.com/crystal-lang/crystal/releases/1.4.0 ### Language - Add support for `Int128` in codegen and macros ([#11576](https://github.com/crystal-lang/crystal/pull/11576), thanks @BlobCodes) - Support `ProcPointer`s with global path and top-level method references ([#11777](https://github.com/crystal-lang/crystal/pull/11777), thanks @HertzDevil) - Fix documentation for macros `system` and `run` ([#11740](https://github.com/crystal-lang/crystal/pull/11740), thanks @lbguilherme) - Experimental: better type inference for ivars/cvars ([#11812](https://github.com/crystal-lang/crystal/pull/11812), thanks @asterite) - Support `@[Deprecated]` on constants ([#11680](https://github.com/crystal-lang/crystal/pull/11680), thanks @HertzDevil) ### Standard Library - Fix compiler flags with optional arg eating following flags ([#11201](https://github.com/crystal-lang/crystal/pull/11201), thanks @yb66) - Support GNU style optional arguments in `OptionParser` ([#11546](https://github.com/crystal-lang/crystal/pull/11546), thanks @HertzDevil) - Remove some unnecessary link annotations ([#11563](https://github.com/crystal-lang/crystal/pull/11563), thanks @straight-shoota) - Remove useless assignments ([#11774](https://github.com/crystal-lang/crystal/pull/11774), thanks @IgorPolyakov) - Use "truthy" and "falsey" in more places in the documentation ([#11784](https://github.com/crystal-lang/crystal/pull/11784), thanks @HertzDevil) - Add missing code blocks for `self` in documentation ([#11718](https://github.com/crystal-lang/crystal/pull/11718), thanks @HertzDevil) - Add support for LLVM 14.0 ([#11905](https://github.com/crystal-lang/crystal/pull/11905), thanks @HertzDevil) - Fix code examples in doc comments (2022-03) ([#11927](https://github.com/crystal-lang/crystal/pull/11927), thanks @maiha) #### Collection - Remove `Iterator.of(Iterator.stop)` from implementations ([#11613](https://github.com/crystal-lang/crystal/pull/11613), thanks @asterite) - Add allow `Enumerable` arguments for `Hash#select` and `#reject` ([#11750](https://github.com/crystal-lang/crystal/pull/11750), thanks @mamantoha) - Add docs for `Hash#reject!` ([#11691](https://github.com/crystal-lang/crystal/pull/11691), thanks @wontruefree) - Add raising method variants `Enumerable#find!` and `#index!` ([#11566](https://github.com/crystal-lang/crystal/pull/11566), thanks @yxhuvud) - **(performance)** Optimize block-less overloads of `BitArray#fill` ([#11450](https://github.com/crystal-lang/crystal/pull/11450), thanks @HertzDevil) - Adds docs for `Array#replace` ([#11682](https://github.com/crystal-lang/crystal/pull/11682), thanks @wontruefree) - **(performance)** Optimize `BitArray`'s counting methods ([#11591](https://github.com/crystal-lang/crystal/pull/11591), thanks @HertzDevil) - Add some return types to Array, Hash, Set and String ([#11822](https://github.com/crystal-lang/crystal/pull/11822), thanks @asterite) - Add `Hash#update` ([#11881](https://github.com/crystal-lang/crystal/pull/11881), thanks @ftarulla) - Allow `Bytes[]` to construct an empty `Bytes` ([#11897](https://github.com/crystal-lang/crystal/pull/11897), thanks @HertzDevil) - Improve `BitArray`'s constructors ([#11898](https://github.com/crystal-lang/crystal/pull/11898), thanks @HertzDevil) - Add overload to `Enumerable#tally` and `#tally_by` accepting a hash ([#11815](https://github.com/crystal-lang/crystal/pull/11815), thanks @mamantoha) #### Crypto - Add support for Bcrypt algorithm version `2b` ([#11595](https://github.com/crystal-lang/crystal/pull/11595), thanks @docelic) #### Files - Fix race condition in `chown` ([#11885](https://github.com/crystal-lang/crystal/pull/11885), thanks @didactic-drunk) - Add docs for `Dir#each_child` ([#11688](https://github.com/crystal-lang/crystal/pull/11688), thanks @wontruefree) - Add docs for `Dir#path` ([#11689](https://github.com/crystal-lang/crystal/pull/11689), thanks @wontruefree) - Support read-write + binary file modes in `File.open` ([#11817](https://github.com/crystal-lang/crystal/pull/11817), thanks @HertzDevil) - Add docs for `Dir#entries` ([#11701](https://github.com/crystal-lang/crystal/pull/11701), thanks @wontruefree) - Add `IO#getb_to_end` ([#11830](https://github.com/crystal-lang/crystal/pull/11830), thanks @HertzDevil) - Fix `IO::FileDescriptor#pos` giving incorrect position after write ([#10865](https://github.com/crystal-lang/crystal/pull/10865), thanks @didactic-drunk) - Remove reference to binary file mode in `File.open` ([#11824](https://github.com/crystal-lang/crystal/pull/11824), thanks @HertzDevil) #### Macros - Add `#parse_type` ([#11126](https://github.com/crystal-lang/crystal/pull/11126), thanks @Blacksmoke16) #### Networking - **(performance)** Optimize `URI.decode` ([#11741](https://github.com/crystal-lang/crystal/pull/11741), thanks @asterite) - Fix `address_spec` expectation for Windows Server 2022 ([#11794](https://github.com/crystal-lang/crystal/pull/11794), thanks @straight-shoota) - Add `space_to_plus` option in `URI::Params` everywhere ([#11821](https://github.com/crystal-lang/crystal/pull/11821), thanks @asterite) - Improve `URI::Params#inspect` to use hash-like literal ([#11880](https://github.com/crystal-lang/crystal/pull/11880), thanks @straight-shoota) - Use enums instead of symbols for `MIME::Multipart` and `HTTP::FormData` ([#11617](https://github.com/crystal-lang/crystal/pull/11617), thanks @HertzDevil) #### Numeric - **(breaking-change)** Fix: Hide `BigDecimal::ZERO` and `BigDecimal::TEN` ([#11820](https://github.com/crystal-lang/crystal/pull/11820), thanks @lbguilherme) - **(breaking-change)** Add support for scientific notation in `BigFloat#to_s` ([#10632](https://github.com/crystal-lang/crystal/pull/10632), thanks @HertzDevil) - Fix: Inspect string in error message for number parsing ([#11883](https://github.com/crystal-lang/crystal/pull/11883), thanks @straight-shoota) - Add docs for `Complex#zero?` ([#11697](https://github.com/crystal-lang/crystal/pull/11697), thanks @wontruefree) - Fix E notation parsing in `BigDecimal` ([#9577](https://github.com/crystal-lang/crystal/pull/9577), thanks @stevegeek) - **(performance)** Optimize Integer decoding from bytes ([#11796](https://github.com/crystal-lang/crystal/pull/11796), thanks @carlhoerberg) #### Runtime - Fix interpreter when shared library `pthread` is missing ([#11807](https://github.com/crystal-lang/crystal/pull/11807), thanks @straight-shoota) - **(performance)** Implement `Intrinsics.pause` for aarch64 ([#11742](https://github.com/crystal-lang/crystal/pull/11742), thanks @lbguilherme, @jgaskins) - Add crash handler on Windows ([#11570](https://github.com/crystal-lang/crystal/pull/11570), thanks @HertzDevil) - Add specs for `NamedTuple#from` ([#11816](https://github.com/crystal-lang/crystal/pull/11816), thanks @straight-shoota) - Improve error for incompatible generic arguments for `WeakRef` ([#11911](https://github.com/crystal-lang/crystal/pull/11911), thanks @straight-shoota) - Add the wasm entrypoint defined in Crystal ([#11936](https://github.com/crystal-lang/crystal/pull/11936), thanks @lbguilherme) #### Serialization - Allow passing instance method or conditional expressions to option `ignore_serialize` on `JSON::Field` ([#11804](https://github.com/crystal-lang/crystal/pull/11804), thanks @cyangle) - Implement `Iterator.from_json` and `#to_json` ([#10437](https://github.com/crystal-lang/crystal/pull/10437), thanks @wonderix) #### Specs - Add `file` and `line` arguments to `it_iterates` ([#11628](https://github.com/crystal-lang/crystal/pull/11628), thanks @straight-shoota) - Remove duplicate word in documentation ([#11797](https://github.com/crystal-lang/crystal/pull/11797), thanks @samueleaton) #### System - **(breaking-change)** **(security)** Fix character mappings for Windows path conversions ([#11847](https://github.com/crystal-lang/crystal/pull/11847), thanks @straight-shoota) - Add fallback for `Path.home` on Unix ([#11544](https://github.com/crystal-lang/crystal/pull/11544), thanks @HertzDevil) - Relax `ENV.fetch(key, &)`'s block restriction ([#11779](https://github.com/crystal-lang/crystal/pull/11779), thanks @HertzDevil) - Refactor target clauses for system implementations ([#11813](https://github.com/crystal-lang/crystal/pull/11813), thanks @straight-shoota) - Fix `Path` support for UNC shares ([#11827](https://github.com/crystal-lang/crystal/pull/11827), thanks @straight-shoota) - Fix regression for Linux older than 3.17: properly check that `getrandom` is available ([#11953](https://github.com/crystal-lang/crystal/pull/11953), thanks @lbguilherme) #### Text - Fix ensure PCRE JIT mode is available before running spec ([#11533](https://github.com/crystal-lang/crystal/pull/11533), thanks @Blacksmoke16) - Add more `Colorize` overloads and fix docs ([#11832](https://github.com/crystal-lang/crystal/pull/11832), thanks @asterite) - Refactor `Colorize::Mode` enum ([#11663](https://github.com/crystal-lang/crystal/pull/11663), thanks @straight-shoota) - Add some docs for `UUID` ([#11683](https://github.com/crystal-lang/crystal/pull/11683), thanks @wontruefree) - Add docs for `UUID#urn` ([#11693](https://github.com/crystal-lang/crystal/pull/11693), thanks @wontruefree) - Add docs for `String#[]` ([#11690](https://github.com/crystal-lang/crystal/pull/11690), thanks @wontruefree) - Allow explicit usage of `libiconv` ([#11876](https://github.com/crystal-lang/crystal/pull/11876), thanks @luislavena) - **(breaking-change)** Fix: Honour encoding in `IO::Memory#to_s` ([#11875](https://github.com/crystal-lang/crystal/pull/11875), thanks @straight-shoota) - Add `self` return type to `UUID` constructor methods ([#10539](https://github.com/crystal-lang/crystal/pull/10539), thanks @straight-shoota) - Fix infinite loop for certain `StringPool` initial capacities ([#11929](https://github.com/crystal-lang/crystal/pull/11929), thanks @HertzDevil) #### Time - Add examples to `Time::Format` methods ([#11713](https://github.com/crystal-lang/crystal/pull/11713), thanks @ThunderKey) - Support day of year (`%j`) in `Time` parsers ([#11791](https://github.com/crystal-lang/crystal/pull/11791), thanks @HertzDevil) ### Compiler - Hello WebAssembly! (MVP implementation) ([#10870](https://github.com/crystal-lang/crystal/pull/10870), thanks @lbguilherme) - Fix compiler specs git integration for configurable default branch ([#11754](https://github.com/crystal-lang/crystal/pull/11754), thanks @yxhuvud) - `Crystal::ToSVisitor`: Remove `decorate_*` methods ([#11724](https://github.com/crystal-lang/crystal/pull/11724), thanks @HertzDevil) - Use fewer symbols in the compiler source ([#11625](https://github.com/crystal-lang/crystal/pull/11625), thanks @HertzDevil) - Add support for `--m*` flags to `crystal spec` and `crystal eval` ([#11767](https://github.com/crystal-lang/crystal/pull/11767), thanks @yxhuvud) - Add local compiler wrapper script for Windows ([#11524](https://github.com/crystal-lang/crystal/pull/11524), thanks @HertzDevil) - Add `Crystal::Program#check_deprecation` ([#11684](https://github.com/crystal-lang/crystal/pull/11684), thanks @HertzDevil) - Refactor symbols for primitive number kinds to enums ([#11621](https://github.com/crystal-lang/crystal/pull/11621), thanks @HertzDevil) - Remove useless assignments II ([#11843](https://github.com/crystal-lang/crystal/pull/11843), thanks @IgorPolyakov) - Limit the number of rendered overloads on signature mismatch ([#10890](https://github.com/crystal-lang/crystal/pull/10890), thanks @caspiano) - Support "can't infer type parameter" error for uninstantiated generic modules ([#11904](https://github.com/crystal-lang/crystal/pull/11904), thanks @HertzDevil) - Fix: Accept only option flags in `CRYSTAL_OPTS` for build commands ([#11922](https://github.com/crystal-lang/crystal/pull/11922), thanks @HertzDevil, @beta-ziliani) - Evaluate `LibLLVM::IS_LT_*` during macro expansion time ([#11913](https://github.com/crystal-lang/crystal/pull/11913), thanks @HertzDevil) - Fix incorrect var type inside nested exception handler ([#11928](https://github.com/crystal-lang/crystal/pull/11928), thanks @asterite) - Fix: Look up return type in defining type ([#11962](https://github.com/crystal-lang/crystal/pull/11962), thanks @asterite) #### Codegen - **(performance)** Codegen: Do not always request value for `Proc#call` ([#11675](https://github.com/crystal-lang/crystal/pull/11675), thanks @HertzDevil) #### Debugger - Fix debug location of inlined `Proc#call` body ([#11676](https://github.com/crystal-lang/crystal/pull/11676), thanks @HertzDevil) #### Generics - Resolve non-type free variables in return type restrictions ([#11861](https://github.com/crystal-lang/crystal/pull/11861), thanks @HertzDevil) - Fix recursive `pointerof` detection with generic splat type variables ([#11811](https://github.com/crystal-lang/crystal/pull/11811), thanks @HertzDevil) #### Interpreter - Fix for Crystal interpreter crash ([#11717](https://github.com/crystal-lang/crystal/pull/11717), thanks @wmoxam) - Interpreter: support `Tuple#[]` with range literals ([#11783](https://github.com/crystal-lang/crystal/pull/11783), thanks @HertzDevil) - Interpreter: Promote arguments of variadic function calls ([#11795](https://github.com/crystal-lang/crystal/pull/11795), thanks @straight-shoota) - Check if libraries are present using `dlopen` ([#11852](https://github.com/crystal-lang/crystal/pull/11852), thanks @FnControlOption) - Use `Crystal::Loader` in the interpreter ([#11579](https://github.com/crystal-lang/crystal/pull/11579), thanks @straight-shoota) - Improve `Crystal::Loader` errors ([#11860](https://github.com/crystal-lang/crystal/pull/11860), thanks @straight-shoota) - Enable interpreter integration specs for `YAML` ([#11801](https://github.com/crystal-lang/crystal/pull/11801), thanks @straight-shoota) #### Parser - Fix parser error with semicolon + newline in parenthesized `Expressions` ([#11769](https://github.com/crystal-lang/crystal/pull/11769), thanks @straight-shoota) - Fix comment indentation in `ASTNode#to_s` ([#11851](https://github.com/crystal-lang/crystal/pull/11851), thanks @FnControlOption) - Add locations for `else`, `ensure`, `end` keywords ([#11476](https://github.com/crystal-lang/crystal/pull/11476), thanks @FnControlOption) - Add parser support to handle CRLF the same as LF ([#11810](https://github.com/crystal-lang/crystal/pull/11810), thanks @asterite) - Lexer: use `Crystal::Token::Kind` enum instead of symbols ([#11616](https://github.com/crystal-lang/crystal/pull/11616), thanks @HertzDevil) - Support `Generic` nodes with no type variables ([#11906](https://github.com/crystal-lang/crystal/pull/11906), thanks @HertzDevil) #### Semantic - **(breaking-change)** Drop `skip_abstract_def_check` flag support ([#9217](https://github.com/crystal-lang/crystal/pull/9217), thanks @makenowjust) - Add error when instance variable is inherited from module and supertype ([#11768](https://github.com/crystal-lang/crystal/pull/11768), thanks @straight-shoota) - Check file-private types for abstract defs and recursive structs ([#11838](https://github.com/crystal-lang/crystal/pull/11838), thanks @HertzDevil) - Fix: Prevent eager `instance_sizeof` on structs ([#11856](https://github.com/crystal-lang/crystal/pull/11856), thanks @mattrberry) - Fix: Do not consider global `Path` in def parameter restriction as free variable ([#11862](https://github.com/crystal-lang/crystal/pull/11862), thanks @HertzDevil) ### Tools - Do not inherit from `Hash` in the compiler ([#11707](https://github.com/crystal-lang/crystal/pull/11707), thanks @HertzDevil) - Use `OptionParser` in `crystal env` ([#11720](https://github.com/crystal-lang/crystal/pull/11720), thanks @HertzDevil) #### Playground - Replace PNG icon with optimized SVG for playground ([#7616](https://github.com/crystal-lang/crystal/pull/7616), thanks @straight-shoota) ### Other - Update previous Crystal release - 1.3.2 ([#11715](https://github.com/crystal-lang/crystal/pull/11715), thanks @straight-shoota) - Add `scripts/release-update.sh` ([#11716](https://github.com/crystal-lang/crystal/pull/11716), thanks @straight-shoota) - [Makefile] Honour `$CC` in `EXPORT_CC` ([#11548](https://github.com/crystal-lang/crystal/pull/11548), thanks @straight-shoota) - Fix typo in GHA aarch64 config ([#11793](https://github.com/crystal-lang/crystal/pull/11793), thanks @straight-shoota) - [CI] Test against LLVM 13 ([#11343](https://github.com/crystal-lang/crystal/pull/11343), thanks @straight-shoota) - [CI] Use parameters in circleci config ([#11714](https://github.com/crystal-lang/crystal/pull/11714), thanks @straight-shoota) - Refactor `etc/completion.bash` ([#11719](https://github.com/crystal-lang/crystal/pull/11719), thanks @HertzDevil) - [CI] Renaming jobs to be `arch-os-job` or `arch-build-job` ([#11207](https://github.com/crystal-lang/crystal/pull/11207), thanks @beta-ziliani) - Improve documentation for review and merge processes ([#11800](https://github.com/crystal-lang/crystal/pull/11800), thanks @straight-shoota) - Improve section ordering in `scripts/github-changelog.cr` ([#11770](https://github.com/crystal-lang/crystal/pull/11770), thanks @straight-shoota) - Upload build artifacts to S3 bucket ([#11902](https://github.com/crystal-lang/crystal/pull/11902), thanks @matiasgarciaisaia, @straight-shoota) - Fix `make install` for BSD ([#11758](https://github.com/crystal-lang/crystal/pull/11758), thanks @straight-shoota) - Fix typo ([#11939](https://github.com/crystal-lang/crystal/pull/11939), thanks @taupiqueur) - [CI] Update to shards 0.17.0 ([#11930](https://github.com/crystal-lang/crystal/pull/11930), thanks @straight-shoota) - Use `be_empty` expectations in more specs ([#11937](https://github.com/crystal-lang/crystal/pull/11937), thanks @HertzDevil) - [CI] Update distribution-scripts ([#11969](https://github.com/crystal-lang/crystal/pull/11969), thanks @straight-shoota) ================================================ FILE: doc/changelogs/v1.5.md ================================================ # Changelog 1.5 ## [1.5.1] - 2022-09-07 [1.5.1]: https://github.com/crystal-lang/crystal/releases/1.5.1 ### Standard Library - Fix `Class#nilable?` for recursive unions and root types ([#12353](https://github.com/crystal-lang/crystal/pull/12353), thanks @HertzDevil) #### Numeric - Fix `Float#abs` and `Number#format` for `-0.0` ([#12424](https://github.com/crystal-lang/crystal/pull/12424), thanks @straight-shoota) #### Text - Fix null dereference when passing empty slice to `Base64.encode` ([#12377](https://github.com/crystal-lang/crystal/pull/12377), thanks @dscottboggs) ### Compiler - Do not check abstract def parameter names on abstract types and modules ([#12434](https://github.com/crystal-lang/crystal/pull/12434), thanks @HertzDevil) #### Codegen - Compiler/codegen: reset `@needs_value` ([#12444](https://github.com/crystal-lang/crystal/pull/12444), thanks @asterite) - Fix `homogeneous_aggregate?` check for aarch64 types ([#12445](https://github.com/crystal-lang/crystal/pull/12445), thanks @mattrberry) #### Semantic - Compiler: don't eagerly check cast type ([#12272](https://github.com/crystal-lang/crystal/pull/12272), thanks @asterite) - Fix type restriction augmenter for `Union(*T)` and similar ([#12438](https://github.com/crystal-lang/crystal/pull/12438), thanks @asterite) ### Tools #### Formatter - Formatter: Fix assign followed by comment ([#12319](https://github.com/crystal-lang/crystal/pull/12319), thanks @straight-shoota) - Handle formatting annotated method parameters ([#12446](https://github.com/crystal-lang/crystal/pull/12446), thanks @Blacksmoke16) ### Other - Update distribution-scripts ([#12359](https://github.com/crystal-lang/crystal/pull/12359), thanks @straight-shoota) - Update distribution-scripts ([#12333](https://github.com/crystal-lang/crystal/pull/12333), thanks @straight-shoota) - [CI] Bumping xcode to 13.4.1 ([#12264](https://github.com/crystal-lang/crystal/pull/12264), thanks @beta-ziliani) ## [1.5.0] - 2022-07-06 [1.5.0]: https://github.com/crystal-lang/crystal/releases/1.5.0 ### Language - **(breaking-change)** Warn on positional parameter mismatches for abstract def implementations ([#11915](https://github.com/crystal-lang/crystal/pull/11915), [#12167](https://github.com/crystal-lang/crystal/pull/12167), thanks @HertzDevil) - Fix `\{{...}}` syntax in macro inside comments ([#12175](https://github.com/crystal-lang/crystal/pull/12175), thanks @asterite) - Let constant tuple indexers work with constants ([#12012](https://github.com/crystal-lang/crystal/pull/12012), thanks @asterite) - Refactor restriction mechanism for autocasting ([#12014](https://github.com/crystal-lang/crystal/pull/12014), thanks @HertzDevil) - Support unions in `Crystal::Macros::ASTNode#is_a?` ([#12086](https://github.com/crystal-lang/crystal/pull/12086), thanks @HertzDevil) - Experimental: restriction augmenter ([#12103](https://github.com/crystal-lang/crystal/pull/12103), [#12136](https://github.com/crystal-lang/crystal/pull/12136), [#12143](https://github.com/crystal-lang/crystal/pull/12143), [#12130](https://github.com/crystal-lang/crystal/pull/12130), thanks @asterite) - Method/macro parameter annotation support ([#12044](https://github.com/crystal-lang/crystal/pull/12044), thanks @Blacksmoke16) ### Standard Library - Support `Path` for `chdir` arg in `Process` methods ([#11932](https://github.com/crystal-lang/crystal/pull/11932), thanks @caspiano) - Add docs for `Enum#value` ([#11947](https://github.com/crystal-lang/crystal/pull/11947), thanks @lbguilherme) - Fix positional parameter warnings in specs ([#12158](https://github.com/crystal-lang/crystal/pull/12158), thanks @straight-shoota) - Use more specific expectations in specs ([#11951](https://github.com/crystal-lang/crystal/pull/11951), thanks @HertzDevil) - Use `contain` expectations in more specs ([#11950](https://github.com/crystal-lang/crystal/pull/11950), thanks @HertzDevil) #### Collection - Fix `Hash#reject!` for non-equality key ([#10511](https://github.com/crystal-lang/crystal/pull/10511), thanks @straight-shoota) - Introduce `Tuple.element_type` and `NamedTuple.element_type` ([#12011](https://github.com/crystal-lang/crystal/pull/12011), thanks @HertzDevil) - Rename "take" to "first" ([#11988](https://github.com/crystal-lang/crystal/pull/11988), thanks @jmdyck) - Add spec for `Array#-` with different generic type arguments ([#12049](https://github.com/crystal-lang/crystal/pull/12049), thanks @straight-shoota) #### Concurrency - Windows: Always use `GC_set_stackbottom` on Windows ([#12186](https://github.com/crystal-lang/crystal/pull/12186), thanks @HertzDevil) - Windows: Event loop based on IOCP ([#12149](https://github.com/crystal-lang/crystal/pull/12149), thanks @straight-shoota, @wonderix, @yxhuvud, @HertzDevil) - Use enum instead of symbol for `Atomic` primitives ([#11583](https://github.com/crystal-lang/crystal/pull/11583), thanks @HertzDevil) - Allow `Enumerable(Channel)` parameter for `Channel.send_first`, `.receive_first` ([#12101](https://github.com/crystal-lang/crystal/pull/12101), thanks @carlhoerberg) #### Crypto - **(performance)** Add faster `Digest#hexfinal` ([#9292](https://github.com/crystal-lang/crystal/pull/9292), thanks @didactic-drunk) - Handle OpenSSL 3.0 KTLS ctrl calls ([#12034](https://github.com/crystal-lang/crystal/pull/12034), thanks @1player) #### Files - Fix `Path#join(Enumerable)` ([#12032](https://github.com/crystal-lang/crystal/pull/12032), thanks @straight-shoota) - Fix `Path#join` to convert argument path to base kind ([#12033](https://github.com/crystal-lang/crystal/pull/12033), thanks @straight-shoota) - Fix `Dir.glob` with multi components after recursive wildcard ([#12057](https://github.com/crystal-lang/crystal/pull/12057), thanks @straight-shoota) - Add `File#delete?` and `Dir#delete?` ([#11887](https://github.com/crystal-lang/crystal/pull/11887), thanks @didactic-drunk) - Accept `Path` arguments in `Compress::Zip` ([#11925](https://github.com/crystal-lang/crystal/pull/11925), thanks @didactic-drunk) - Update file.cr ([#12024](https://github.com/crystal-lang/crystal/pull/12024), thanks @rdp) - Add `File#chown` and `#chmod` ([#11886](https://github.com/crystal-lang/crystal/pull/11886), thanks @didactic-drunk) #### Log - Change `Log` emitters to not emit event when block output is `nil` ([#12000](https://github.com/crystal-lang/crystal/pull/12000), thanks @robacarp) #### Networking - Enable more networking specs on Windows ([#12176](https://github.com/crystal-lang/crystal/pull/12176), thanks @HertzDevil) - Add specs for Windows directory separators in `StaticFileHandler` paths ([#11884](https://github.com/crystal-lang/crystal/pull/11884), thanks @straight-shoota) - Add property `HTTP::Server::Response#status_message` ([#10416](https://github.com/crystal-lang/crystal/pull/10416), thanks @straight-shoota) #### Numeric - Fix `Complex.multiplicative_identity` ([#12051](https://github.com/crystal-lang/crystal/pull/12051), thanks @I3oris) - Add docs for `Float`, `BigFloat` rounding methods ([#12004](https://github.com/crystal-lang/crystal/pull/12004), thanks @marksiemers) - Implement rt builtins `__ashlti3`, `__ashrti3` and `__lshrti3` for wasm32 ([#11948](https://github.com/crystal-lang/crystal/pull/11948), thanks @lbguilherme) #### Specs - Align `Spec::Be`, `BeClose` failure message to other messages ([#11946](https://github.com/crystal-lang/crystal/pull/11946), thanks @jgaskins) #### System - **(security)** Fix check for null byte in `File#tempfile` args ([#12076](https://github.com/crystal-lang/crystal/pull/12076), thanks @straight-shoota) - Add missing `SC_PAGESIZE` constant for `aarch64-darwin` ([#12037](https://github.com/crystal-lang/crystal/pull/12037), thanks @carlhoerberg) - Docs: Add more prominent note about path traversal in `File.tempfile` ([#12077](https://github.com/crystal-lang/crystal/pull/12077), thanks @straight-shoota) - Support `Enumerable` as argument to `File.join` ([#12102](https://github.com/crystal-lang/crystal/pull/12102), thanks @caspiano) #### Runtime - Mention `#value` explicitly in `Pointer` overview. ([#12184](https://github.com/crystal-lang/crystal/pull/12184), thanks @elebow) #### Text - Add specs for `String#char_bytesize_at` ([#11872](https://github.com/crystal-lang/crystal/pull/11872), thanks @straight-shoota) - Flush shift state for `String#encode` ([#11993](https://github.com/crystal-lang/crystal/pull/11993), thanks @HertzDevil) - Handle invalid bytes in single-byte optimizable `String`s correctly ([#12108](https://github.com/crystal-lang/crystal/pull/12108), thanks @HertzDevil) - Fix: Don't stop on null byte in `String#%` ([#12125](https://github.com/crystal-lang/crystal/pull/12125), thanks @asterite) - Add `UUID.parse?` ([#11998](https://github.com/crystal-lang/crystal/pull/11998), thanks @jgaskins) #### Time - Fix: Better error message for `Time.parse!` when end of input is reached ([#12124](https://github.com/crystal-lang/crystal/pull/12124), thanks @asterite) ### Compiler - Clean up compiler warning specs ([#11916](https://github.com/crystal-lang/crystal/pull/11916), thanks @HertzDevil) - Add support for `NO_COLOR` to `Colorize` ([#11984](https://github.com/crystal-lang/crystal/pull/11984), thanks @didactic-drunk) - **(performance)** Use LLVM's new pass manager when possible ([#12116](https://github.com/crystal-lang/crystal/pull/12116), thanks @asterite) #### Macros - Document `Crystal::Macros::Self` and `Underscore` ([#12085](https://github.com/crystal-lang/crystal/pull/12085), thanks @HertzDevil) #### Generics - Allow the empty instantiation `NamedTuple()` ([#12009](https://github.com/crystal-lang/crystal/pull/12009), thanks @HertzDevil) #### Interpreter - Add missing `EXPORT` in interpreter spec ([#12201](https://github.com/crystal-lang/crystal/pull/12201), thanks @HertzDevil) - Handle escaping exceptions in pry ([#12211](https://github.com/crystal-lang/crystal/pull/12211), thanks @asterite) - Allow some options, and colorize whereami ([#12198](https://github.com/crystal-lang/crystal/pull/12198), thanks @asterite) - Fix instance var offset of virtual struct ([#12189](https://github.com/crystal-lang/crystal/pull/12189), thanks @asterite) - Handle explicit return when method type is Nil ([#12179](https://github.com/crystal-lang/crystal/pull/12179), thanks @asterite) - `Crystal::Loader`: don't check if file exists, leave that to dlopen ([#12207](https://github.com/crystal-lang/crystal/pull/12207), thanks @asterite) - Fix call receiver by value from VirtualType struct ([#12194](https://github.com/crystal-lang/crystal/pull/12194), thanks @asterite) - Clear finished hooks after interpreting ([#12174](https://github.com/crystal-lang/crystal/pull/12174), thanks @asterite) - Fix FFI bindings for libffi >= 3.4 ([#12192](https://github.com/crystal-lang/crystal/pull/12192), thanks @straight-shoota) - Fix `.class` for modules and unions ([#12205](https://github.com/crystal-lang/crystal/pull/12205), thanks @asterite) - Implement `Crystal::Loader` for MSVC ([#12140](https://github.com/crystal-lang/crystal/pull/12140), thanks @HertzDevil) - Fix: cast from virtual metaclass to union ([#12163](https://github.com/crystal-lang/crystal/pull/12163), thanks @asterite) - Allow inspect vars when inside a block ([#12165](https://github.com/crystal-lang/crystal/pull/12165), thanks @asterite) - Let pry see closured vars ([#12169](https://github.com/crystal-lang/crystal/pull/12169), thanks @asterite) - Fix caller ([#12182](https://github.com/crystal-lang/crystal/pull/12182), thanks @asterite) - Apply shell expansion in ldflags ([#12094](https://github.com/crystal-lang/crystal/pull/12094), thanks @mdwagner) - Fix expression value of constant assignment in interpreter ([#12016](https://github.com/crystal-lang/crystal/pull/12016), thanks @beta-ziliani) - Fix: Don't link `librt` and `libdl` on GNU systems ([#12038](https://github.com/crystal-lang/crystal/pull/12038), thanks @1player) #### Parser - **(breaking-change)** Disallow empty parameter and argument names ([#11971](https://github.com/crystal-lang/crystal/pull/11971), thanks @HertzDevil) - Disallow duplicate free variables in defs ([#11965](https://github.com/crystal-lang/crystal/pull/11965), thanks @HertzDevil) - Disallow duplicate `fun` parameter names ([#11967](https://github.com/crystal-lang/crystal/pull/11967), thanks @HertzDevil) - Remove redundant check for EOF on `Crystal::Parser` ([#12067](https://github.com/crystal-lang/crystal/pull/12067), thanks @lbguilherme) #### Semantic - Compiler: don't check ivar read forms a closure in `exp.@x` ([#12183](https://github.com/crystal-lang/crystal/pull/12183), thanks @asterite) - Compiler: raise when allocating an abstract virtual type ([#12141](https://github.com/crystal-lang/crystal/pull/12141), thanks @asterite) - Compiler: don't use `with_scope` if Call has a receiver ([#12138](https://github.com/crystal-lang/crystal/pull/12138), thanks @asterite) - Compiler: fix proc return type restriction for `Proc(...)` ([#12129](https://github.com/crystal-lang/crystal/pull/12129), thanks @asterite) - Compiler: simpler way to compute `Def#raises?` ([#12121](https://github.com/crystal-lang/crystal/pull/12121), thanks @asterite) - Remove unused `ASTNode#unbind_all` ([#12120](https://github.com/crystal-lang/crystal/pull/12120), thanks @asterite) #### Debugger - Improve the LLDB spec driver script ([#12119](https://github.com/crystal-lang/crystal/pull/12119), thanks @HertzDevil) ### Tools #### Docs-generator - [Docs] Adjust method sort order to sort all operators first ([#12104](https://github.com/crystal-lang/crystal/pull/12104), thanks @straight-shoota) #### Formatter - Fix formatter lib-fun declaration with newlines ([#12071](https://github.com/crystal-lang/crystal/pull/12071), thanks @ftarulla) - Fix formatter alias-def with no-space before equals ([#12073](https://github.com/crystal-lang/crystal/pull/12073), thanks @ftarulla) - Fix formatter for parenthesized arg after space ([#11972](https://github.com/crystal-lang/crystal/pull/11972), thanks @straight-shoota) #### Playground - Playground: fix `modalContentDom` typo ([#12188](https://github.com/crystal-lang/crystal/pull/12188), thanks @HertzDevil) - Fix: Unset executable bit from js/css files in playground ([#12053](https://github.com/crystal-lang/crystal/pull/12053), thanks @carlhoerberg) ### Other - [CI] Add build compiler step to smoke tests ([#11814](https://github.com/crystal-lang/crystal/pull/11814), thanks @straight-shoota) - Add Makefile for Windows ([#11773](https://github.com/crystal-lang/crystal/pull/11773), thanks @HertzDevil) - [CI] Update distribution-scripts ([#12155](https://github.com/crystal-lang/crystal/pull/12155), thanks @straight-shoota) - [CI] Add `update-distributions-scripts.sh` ([#12156](https://github.com/crystal-lang/crystal/pull/12156), thanks @straight-shoota) - [CI] Ignore `pax_global_header` on Windows CI ([#12173](https://github.com/crystal-lang/crystal/pull/12173), thanks @HertzDevil) - [CI] Invalidate cached libraries on new MSVC release ([#12064](https://github.com/crystal-lang/crystal/pull/12064), thanks @HertzDevil) - Fix spelling ([#12040](https://github.com/crystal-lang/crystal/pull/12040), thanks @jsoref) - Update previous Crystal release - 1.4.1 ([#12029](https://github.com/crystal-lang/crystal/pull/12029), thanks @straight-shoota) - [CI] Pin version of ubuntu base image for circleci jobs ([#12030](https://github.com/crystal-lang/crystal/pull/12030), thanks @straight-shoota) - Samples: avoid `Symbol` variables ([#11923](https://github.com/crystal-lang/crystal/pull/11923), thanks @HertzDevil) ================================================ FILE: doc/changelogs/v1.6.md ================================================ # Changelog 1.6 ## [1.6.2] - 2022-11-03 [1.6.2]: https://github.com/crystal-lang/crystal/releases/1.6.2 ### Language - Fix `VirtualMetaclassType#implements?` to ignore base type ([#12632](https://github.com/crystal-lang/crystal/pull/12632), thanks @straight-shoota) ### Compiler - Compiler: handle yield expressions without a type ([#12679](https://github.com/crystal-lang/crystal/pull/12679), thanks @asterite) - Partial revert "Compiler: refactor and slightly optimize merging two types (#12436)" ([#12709](https://github.com/crystal-lang/crystal/pull/12709), thanks @caspiano) #### Semantic - Compiler: ignore type filters when accepting cast for `obj` and `to` ([#12668](https://github.com/crystal-lang/crystal/pull/12668), thanks @asterite) ### Other - **(security)** CI: Update to OpenSSL 3.0.7 for bundled lib on Windows ([#12712](https://github.com/crystal-lang/crystal/pull/12712), thanks @beta-ziliani) ## [1.6.1] - 2022-10-21 [1.6.1]: https://github.com/crystal-lang/crystal/releases/1.6.1 ### Compiler #### Interpreter - Interpreter (repl): migrate types even if their size remains the same ([#12581](https://github.com/crystal-lang/crystal/pull/12581), thanks @asterite) - Unbreak the interpreter on FreeBSD ([#12600](https://github.com/crystal-lang/crystal/pull/12600), thanks @dmgk) - Fix FFI specs on release builds ([#12601](https://github.com/crystal-lang/crystal/pull/12601), thanks @HertzDevil) - Adding welcome message to the interpreter ([#12511](https://github.com/crystal-lang/crystal/pull/12511), thanks @beta-ziliani) #### Semantic - Treat single splats with same restriction as equivalent ([#12584](https://github.com/crystal-lang/crystal/pull/12584), thanks @HertzDevil) ### Tools #### Formatter - Formatter: escape backslashes in macro literals when subformatting ([#12582](https://github.com/crystal-lang/crystal/pull/12582), thanks @asterite) #### Playground - Fix origin validation in playground server for localhost ([#12599](https://github.com/crystal-lang/crystal/pull/12599), thanks @straight-shoota) ### Other - Fix doc typos in `Socket::IPAddress` ([#12583](https://github.com/crystal-lang/crystal/pull/12583), thanks @Blacksmoke16) - Fix building Wasm32 on Crystal 1.6 (Regression) ([#12580](https://github.com/crystal-lang/crystal/pull/12580), thanks @lbguilherme) - Bump version to 1.6.1-dev ([#12588](https://github.com/crystal-lang/crystal/pull/12588), thanks @straight-shoota) - Disable failing specs on Windows CI ([#12585](https://github.com/crystal-lang/crystal/pull/12585), thanks @HertzDevil) - Detect `llvm-configXX` while building compiler ([#12602](https://github.com/crystal-lang/crystal/pull/12602), thanks @HertzDevil) ## [1.6.0] - 2022-10-06 [1.6.0]: https://github.com/crystal-lang/crystal/releases/1.6.0 ### Language - Add 'wasm_import_module' option to the `@[Link]` annotation ([#11935](https://github.com/crystal-lang/crystal/pull/11935), thanks @lbguilherme) ### Standard Library - Use `GC.malloc_atomic` with `GC.realloc`, not `Pointer#realloc` ([#12391](https://github.com/crystal-lang/crystal/pull/12391), thanks @HertzDevil) - Improve syntax highlighter ([#12409](https://github.com/crystal-lang/crystal/pull/12409), thanks @I3oris) - Enable miscellaneous parts of the standard library on Windows ([#12281](https://github.com/crystal-lang/crystal/pull/12281), thanks @HertzDevil) - Use interpreter to run std spec tests ([#12355](https://github.com/crystal-lang/crystal/pull/12355), thanks @cyangle) - Remove most uses of `Symbol` variables in standard library specs ([#12462](https://github.com/crystal-lang/crystal/pull/12462), thanks @HertzDevil) - Use `@[::Primitive]` and `@[::Flags]` where necessary ([#11900](https://github.com/crystal-lang/crystal/pull/11900), thanks @HertzDevil) - Document how to change base type of an enum ([#9803](https://github.com/crystal-lang/crystal/pull/9803), thanks @Blacksmoke16) - Spec: bump and document timeouts in interpreted mode ([#12430](https://github.com/crystal-lang/crystal/pull/12430), thanks @asterite) #### Collection - Refactor and improve `NamedTuple` deserialization from JSON and YAML ([#12008](https://github.com/crystal-lang/crystal/pull/12008), thanks @HertzDevil) - **(performance)** Optimize `BitArray#tally(hash)` ([#11909](https://github.com/crystal-lang/crystal/pull/11909), thanks @HertzDevil) - Use `Slice#unsafe_slice_of` and `#to_unsafe_bytes` in the standard library and compiler ([#12280](https://github.com/crystal-lang/crystal/pull/12280), thanks @HertzDevil) - **(performance)** Optimize block-less overloads of `BitArray#index` and `#rindex` ([#12087](https://github.com/crystal-lang/crystal/pull/12087), thanks @HertzDevil) - Support tuple metaclass indexers with non-literal arguments ([#11834](https://github.com/crystal-lang/crystal/pull/11834), thanks @HertzDevil) - Add `Indexable#index!` overloads with `offset` parameter ([#12089](https://github.com/crystal-lang/crystal/pull/12089), thanks @HertzDevil) #### Concurrency - Fix fiber clean loop on Windows ([#12300](https://github.com/crystal-lang/crystal/pull/12300), thanks @HertzDevil) - Enable `Mutex` on Windows ([#12213](https://github.com/crystal-lang/crystal/pull/12213), thanks @HertzDevil) #### Crypto - Add support for Bcrypt algorithm version 2y ([#12447](https://github.com/crystal-lang/crystal/pull/12447), thanks @docelic) - Allow using `U/Int128` in `Random` ([#11977](https://github.com/crystal-lang/crystal/pull/11977), thanks @BlobCodes) #### Files - **(breaking-change)** Define `#system_echo` and `#system_raw` on all systems ([#12352](https://github.com/crystal-lang/crystal/pull/12352), thanks @HertzDevil) - **(breaking-change)** Do not expose `Crystal::System::FileInfo` through `File::Info` ([#12385](https://github.com/crystal-lang/crystal/pull/12385), thanks @HertzDevil) - Fix `IO.pipe` spec on FreeBSD ([#12324](https://github.com/crystal-lang/crystal/pull/12324), thanks @dmgk) - Fix docs error for `File.match?` `**` globbing pattern. ([#12343](https://github.com/crystal-lang/crystal/pull/12343), thanks @zw963) - Add `Dir#info` ([#11991](https://github.com/crystal-lang/crystal/pull/11991), thanks @didactic-drunk) - Implement `IO::FileDescriptor`'s console methods on Windows ([#12294](https://github.com/crystal-lang/crystal/pull/12294), thanks @HertzDevil) - Fix typo: `LibC::DT_LINK` -> `DT_LNK` ([#11954](https://github.com/crystal-lang/crystal/pull/11954), thanks @HertzDevil) - Document `IO::FileDescriptor#info` ([#12384](https://github.com/crystal-lang/crystal/pull/12384), thanks @HertzDevil) - **(performance)** Introduce `IO::DEFAULT_BUFFER_SIZE` ([#12507](https://github.com/crystal-lang/crystal/pull/12507), thanks @straight-shoota) - Add support for `IO::FileDescriptor` staying open on finalize ([#12367](https://github.com/crystal-lang/crystal/pull/12367), thanks @refi64) #### Macros - Enhance `record` documentation ([#12334](https://github.com/crystal-lang/crystal/pull/12334), thanks @straight-shoota) #### Networking - Add `Socket::IPAddress.valid?` ([#12489](https://github.com/crystal-lang/crystal/pull/12489), [#10492](https://github.com/crystal-lang/crystal/pull/10492), thanks @straight-shoota) - Fix `HTTP::Client#exec` to abort retry when client was closed ([#12465](https://github.com/crystal-lang/crystal/pull/12465), thanks @straight-shoota) - Fix specs with side effects ([#12539](https://github.com/crystal-lang/crystal/pull/12539), thanks @straight-shoota) - Fix `HTTP::Client` implicit compression with retry ([#12536](https://github.com/crystal-lang/crystal/pull/12536), thanks @straight-shoota) - `HTTP::StaticFileHandler`: Reduce max stat calls from 6 to 2 ([#12310](https://github.com/crystal-lang/crystal/pull/12310), thanks @didactic-drunk) - Add warning about concurrent requests in `HTTP::Client` ([#12527](https://github.com/crystal-lang/crystal/pull/12527), thanks @straight-shoota) #### Numeric - Add full integer support to `sprintf` and `String#%` ([#10973](https://github.com/crystal-lang/crystal/pull/10973), thanks @HertzDevil) - Make `Float#to_s` ignore NaN sign bit ([#12399](https://github.com/crystal-lang/crystal/pull/12399), thanks @HertzDevil) - Make `sprintf` and `String#%` ignore NaN sign bit ([#12400](https://github.com/crystal-lang/crystal/pull/12400), thanks @HertzDevil) - Fix `Complex#to_s` imaginary component sign for certain values ([#12244](https://github.com/crystal-lang/crystal/pull/12244), thanks @HertzDevil) - More accurate definition of `Complex#sign` ([#12242](https://github.com/crystal-lang/crystal/pull/12242), thanks @HertzDevil) - Fix overflow for `rand(Range(Int, Int))` when signed span is too large ([#12545](https://github.com/crystal-lang/crystal/pull/12545), thanks @HertzDevil) - **(performance)** Add `#rotate_left` and `#rotate_right` for primitive integers ([#12307](https://github.com/crystal-lang/crystal/pull/12307), thanks @HertzDevil) - **(performance)** Optimize `BigDecimal#div` for inexact divisions ([#10803](https://github.com/crystal-lang/crystal/pull/10803), thanks @HertzDevil) - Implement the Dragonbox algorithm for `Float#to_s` ([#10913](https://github.com/crystal-lang/crystal/pull/10913), thanks @HertzDevil) - Add `U/Int128` to `isqrt` spec ([#11976](https://github.com/crystal-lang/crystal/pull/11976), thanks @BlobCodes) #### Runtime - Fix: Parse DWARF5 Data16 values ([#12497](https://github.com/crystal-lang/crystal/pull/12497), thanks @stakach) - macOS: Fix call stack when executable path contains symlinks ([#12504](https://github.com/crystal-lang/crystal/pull/12504), thanks @HertzDevil) - WASM: Add support for `wasi-sdk 16`: don't rely on `__original_main` ([#12450](https://github.com/crystal-lang/crystal/pull/12450), thanks @lbguilherme) #### Serialization - Fix YAML serialization class name ambiguity ([#12537](https://github.com/crystal-lang/crystal/pull/12537), thanks @hugopl) - Allow non-type converter instances in `ArrayConverter` and `HashValueConverter` ([#10638](https://github.com/crystal-lang/crystal/pull/10638), thanks @HertzDevil) - Document `after_initialize` method for `yaml` and `json` serializers ([#12530](https://github.com/crystal-lang/crystal/pull/12530), thanks @analogsalad) #### System - Add missing fields to `LibC::Passwd` on FreeBSD ([#12315](https://github.com/crystal-lang/crystal/pull/12315), thanks @dmgk) - Add platform-specific variants of `Process.parse_arguments` ([#12278](https://github.com/crystal-lang/crystal/pull/12278), thanks @HertzDevil) - Make `Dir.current` respect `$PWD` ([#12471](https://github.com/crystal-lang/crystal/pull/12471), thanks @straight-shoota) #### Text - Fix `String` shift state specs on FreeBSD ([#12339](https://github.com/crystal-lang/crystal/pull/12339), thanks @dmgk) - Disallow mixing of sequential and named `sprintf` parameters ([#12402](https://github.com/crystal-lang/crystal/pull/12402), thanks @HertzDevil) - Fix `Colorize` doc example ([#12492](https://github.com/crystal-lang/crystal/pull/12492), thanks @zw963) - **(performance)** Optimize `String#downcase` and `String#upcase` for single byte optimizable case ([#12389](https://github.com/crystal-lang/crystal/pull/12389), thanks @asterite) - **(performance)** Optimize `String#valid_encoding?` ([#12145](https://github.com/crystal-lang/crystal/pull/12145), thanks @HertzDevil) - Implement `String#unicode_normalize` and `String#unicode_normalized?` ([#11226](https://github.com/crystal-lang/crystal/pull/11226), thanks @HertzDevil) - Support parameter numbers in `sprintf` ([#12448](https://github.com/crystal-lang/crystal/pull/12448), thanks @HertzDevil) - Use `LibC.malloc` instead of `GC.malloc` for LibPCRE allocations ([#12456](https://github.com/crystal-lang/crystal/pull/12456), thanks @lbguilherme) - Unicode: Update to version 15.0.0 ([#12479](https://github.com/crystal-lang/crystal/pull/12479), thanks @HertzDevil) - Avoid free call in interpreted mode ([#12496](https://github.com/crystal-lang/crystal/pull/12496), thanks @straight-shoota) ### Compiler - Improve recursive splat expansion detection ([#11790](https://github.com/crystal-lang/crystal/pull/11790), thanks @asterite) - Compiler: fix `#to_s` for empty parameters of lib funs ([#12368](https://github.com/crystal-lang/crystal/pull/12368), thanks @HertzDevil) - Compiler: transform `Proc(*T, Void)` to `Proc(*T, Nil)` ([#12388](https://github.com/crystal-lang/crystal/pull/12388), thanks @asterite) - Compiler: indent `begin` `Expression`s that are direct node children ([#12362](https://github.com/crystal-lang/crystal/pull/12362), thanks @HertzDevil) - Compiler: add missing location to node on literal expander for array ([#12403](https://github.com/crystal-lang/crystal/pull/12403), thanks @asterite) - Compiler: a generic class type can also be reference-like ([#12347](https://github.com/crystal-lang/crystal/pull/12347), thanks @asterite) - Hoist complex element expressions outside container literals ([#12366](https://github.com/crystal-lang/crystal/pull/12366), thanks @HertzDevil) - **(performance)** Compiler: bind to tuple, not array ([#12423](https://github.com/crystal-lang/crystal/pull/12423), thanks @asterite) - Use `Path.new(string)` instead of `Path.new([string])` ([#12419](https://github.com/crystal-lang/crystal/pull/12419), thanks @asterite) - Decouple warning detection from program instances ([#12293](https://github.com/crystal-lang/crystal/pull/12293), thanks @HertzDevil) - **(performance)** Compiler: only have `freeze_type` in select AST nodes ([#12428](https://github.com/crystal-lang/crystal/pull/12428), thanks @asterite) - Correctly display codegen when cross-compiling ([#12414](https://github.com/crystal-lang/crystal/pull/12414), thanks @luislavena) - Compiler: simplify some calls ([#12417](https://github.com/crystal-lang/crystal/pull/12417), thanks @asterite) - **(performance)** Compiler: optimizations in `merge_if_vars` ([#12432](https://github.com/crystal-lang/crystal/pull/12432), [#12433](https://github.com/crystal-lang/crystal/pull/12433), thanks @asterite) - Compiler refactor: extract `type_from_dependencies` ([#12437](https://github.com/crystal-lang/crystal/pull/12437), thanks @asterite) - **(performance)** Compiler: refactor and slightly optimize merging two types ([#12436](https://github.com/crystal-lang/crystal/pull/12436), thanks @asterite) - **(performance)** Compiler optimization: don't create call for hook unless needed ([#12452](https://github.com/crystal-lang/crystal/pull/12452), thanks @asterite) - **(performance)** CrystalPath: Cache `Dir.current` to avoid thousands of allocations ([#12455](https://github.com/crystal-lang/crystal/pull/12455), thanks @yxhuvud) - Better call error messages ([#12469](https://github.com/crystal-lang/crystal/pull/12469), thanks @asterite) - **(performance)** Compiler optimization: avoid intermediate array when matching call arg types ([#12485](https://github.com/crystal-lang/crystal/pull/12485), thanks @asterite) #### Codegen - Codegen: fix how unions are represented to not miss bytes ([#12551](https://github.com/crystal-lang/crystal/pull/12551), thanks @asterite) - Fix alignment typo in compiler comments ([#12564](https://github.com/crystal-lang/crystal/pull/12564), thanks @mdwagner) - Remove redundant code from x86_64 abi ([#12443](https://github.com/crystal-lang/crystal/pull/12443), thanks @mattrberry) - Codegen: use var pointer for `out` instead of an extra variable ([#10952](https://github.com/crystal-lang/crystal/pull/10952), thanks @asterite) #### Debugger - Basic GDB formatter support ([#12209](https://github.com/crystal-lang/crystal/pull/12209), thanks @HertzDevil) - Add Visual Studio formatters for `String`, `Array`, and `Hash` ([#12212](https://github.com/crystal-lang/crystal/pull/12212), thanks @HertzDevil) #### Interpreter - Interpreter: handle the case of a def's body with no type ([#12220](https://github.com/crystal-lang/crystal/pull/12220), thanks @asterite) - Interpreter: simplify ivar initialization ([#12222](https://github.com/crystal-lang/crystal/pull/12222), thanks @asterite) - Interpreter: fix autocasting in multidispatch ([#12223](https://github.com/crystal-lang/crystal/pull/12223), thanks @asterite) - Interpreter: handle `next` inside captured block ([#12237](https://github.com/crystal-lang/crystal/pull/12237), thanks @asterite) - Interpreter: fix `crystal_type_id` for virtual metaclass type ([#12246](https://github.com/crystal-lang/crystal/pull/12246), thanks @asterite) - Interpreter: handle yield with splat combined with tuple unpacking ([#12247](https://github.com/crystal-lang/crystal/pull/12247), thanks @asterite) - Interpreter: handle inlined call that returns self for structs ([#12259](https://github.com/crystal-lang/crystal/pull/12259), thanks @asterite) - Interpreter: implement `Int128`/`UInt128` intrinsics ([#12258](https://github.com/crystal-lang/crystal/pull/12258), thanks @asterite) - Interpreter: fix some conversion primitives ([#12257](https://github.com/crystal-lang/crystal/pull/12257), thanks @asterite) - Interpreter: don't override special vars inside block ([#12251](https://github.com/crystal-lang/crystal/pull/12251), thanks @asterite) - Interpreter: add missing cast from tuple to other tuple inside union ([#12249](https://github.com/crystal-lang/crystal/pull/12249), thanks @asterite) - Interpreter: allow declaring local vars during a pry session ([#12180](https://github.com/crystal-lang/crystal/pull/12180), thanks @asterite) - Interpreter: handle bitreverse intrinsics ([#12273](https://github.com/crystal-lang/crystal/pull/12273), thanks @asterite) - Interpreter: cache methods with captured block ([#12285](https://github.com/crystal-lang/crystal/pull/12285), thanks @asterite) - Interpreter: missing downcast from `MixedUnionType` to `NilableProcType` ([#12286](https://github.com/crystal-lang/crystal/pull/12286), thanks @asterite) - Interpreter: fix `with ... yield` with extra arguments ([#12301](https://github.com/crystal-lang/crystal/pull/12301), thanks @asterite) - Interpreter: consider nodes without a type as `NoReturn` ([#12275](https://github.com/crystal-lang/crystal/pull/12275), thanks @asterite) - Interpreter: take `with ... yield` scope into account for args bytesize ([#12317](https://github.com/crystal-lang/crystal/pull/12317), thanks @asterite) - Fix loader spec on FreeBSD ([#12323](https://github.com/crystal-lang/crystal/pull/12323), thanks @dmgk) - Interpreter: inline ivar access for virtual call with a single child ([#12321](https://github.com/crystal-lang/crystal/pull/12321), thanks @asterite) - Interpreter: fix `as?` when there's no resulting type ([#12328](https://github.com/crystal-lang/crystal/pull/12328), thanks @asterite) - Interpreter: handle missing closured struct self ([#12345](https://github.com/crystal-lang/crystal/pull/12345), thanks @asterite) - Interpreter: use `non_nilable_type` in NilableCast ([#12348](https://github.com/crystal-lang/crystal/pull/12348), thanks @asterite) - Interpreter: implement mixed union cast with compatible tuple types ([#12349](https://github.com/crystal-lang/crystal/pull/12349), thanks @asterite) - Interpreter: fix missing `upcast_distinct` from `A+` to `B` (`Crystal::VirtualType` to `Crystal::NonGenericClassType`) ([#12374](https://github.com/crystal-lang/crystal/pull/12374), thanks @asterite) - Interpreter: discard tuple and named tuple ([#12387](https://github.com/crystal-lang/crystal/pull/12387), thanks @asterite) - Interpreter: cast proc call arguments to proc arg types ([#12375](https://github.com/crystal-lang/crystal/pull/12375), thanks @asterite) - Interpreter: set correct scope for class var initializer ([#12441](https://github.com/crystal-lang/crystal/pull/12441), thanks @asterite) - Interpreter (repl): use new `MainVisitor` each time we need to interpret code ([#12512](https://github.com/crystal-lang/crystal/pull/12512), thanks @asterite) - Interpreter: allow inspecting block vars without affecting program ([#12520](https://github.com/crystal-lang/crystal/pull/12520), thanks @asterite) - Interpreter: check upcast in nilable cast ([#12533](https://github.com/crystal-lang/crystal/pull/12533), thanks @asterite) - Interpreter: implement variable autocast ([#12563](https://github.com/crystal-lang/crystal/pull/12563), thanks @asterite) - Interpreter: handle missing upcast from `GenericClassInstanceMetaclassType` to `VirtualMetaclassType` ([#12562](https://github.com/crystal-lang/crystal/pull/12562), thanks @asterite) - Interpreter: let local vars be seen by macros in repl and pry ([#12240](https://github.com/crystal-lang/crystal/pull/12240), thanks @asterite) - Interpreter: handle local variable type declaration ([#12239](https://github.com/crystal-lang/crystal/pull/12239), thanks @asterite) - Support libffi on Windows ([#12200](https://github.com/crystal-lang/crystal/pull/12200), thanks @HertzDevil) - Add `$CRYSTAL_INTERPRETER_LOADER_INFO` to show loaded libraries ([#12221](https://github.com/crystal-lang/crystal/pull/12221), thanks @straight-shoota) - Interpreter: node override ([#12287](https://github.com/crystal-lang/crystal/pull/12287), thanks @asterite) - Interpreter: introduce a `Prompt` type ([#12288](https://github.com/crystal-lang/crystal/pull/12288), thanks @asterite) - Interpreter: missing `i += 1` ([#12381](https://github.com/crystal-lang/crystal/pull/12381), thanks @asterite) - Support building the interpreter on Windows ([#12397](https://github.com/crystal-lang/crystal/pull/12397), thanks @HertzDevil) - Don't exit in interpreter spec and change type from `Nil` to `NoReturn` in `FixMissingTypes` ([#12230](https://github.com/crystal-lang/crystal/pull/12230), thanks @asterite) - Interpreter: fix multidispatch with captured block ([#12236](https://github.com/crystal-lang/crystal/pull/12236), thanks @asterite) - Interpreter: don't change compiled mode logic ([#12252](https://github.com/crystal-lang/crystal/pull/12252), thanks @asterite) - Wait more in `HTTP::Server` specs in interpreted mode ([#12420](https://github.com/crystal-lang/crystal/pull/12420), thanks @asterite) #### Parser - Lexer: fix index out of bounds when scanning numbers ([#12482](https://github.com/crystal-lang/crystal/pull/12482), thanks @asterite) - Fix parser to never create doc from trailing comment ([#11268](https://github.com/crystal-lang/crystal/pull/11268), thanks @straight-shoota) - Parser: declare local vars of indirect type declarations in call args ([#11983](https://github.com/crystal-lang/crystal/pull/11983), thanks @asterite) - Remove redundant conditional ([#12196](https://github.com/crystal-lang/crystal/pull/12196), thanks @potomak) - Warn on suffix-less integer literals outside `Int64`'s range ([#12427](https://github.com/crystal-lang/crystal/pull/12427), thanks @HertzDevil) - Use enum instead of symbols for keywords in the lexer ([#11871](https://github.com/crystal-lang/crystal/pull/11871), thanks @HertzDevil) - Parser: Rename `arg*` to `param*` ([#12235](https://github.com/crystal-lang/crystal/pull/12235), thanks @potomak) - Fix test cases ([#12508](https://github.com/crystal-lang/crystal/pull/12508), thanks @potomak) #### Semantic - **(breaking-change)** Allow `Union` restrictions to be ordered before all other restrictions ([#12335](https://github.com/crystal-lang/crystal/pull/12335), thanks @HertzDevil) - **(breaking-change)** Use more robust ordering between def overloads ([#10711](https://github.com/crystal-lang/crystal/pull/10711), thanks @HertzDevil) - Fix: Instance vars should not be allowed on `Class`, `Tuple`, `NamedTuple`, `Enum`, `Pointer` , `Proc`, `StaticArray` and `Union`. ([#12160](https://github.com/crystal-lang/crystal/pull/12160), thanks @I3oris) - Compiler and interpreter: fix `is_a?` from virtual metaclass to generic metaclass ([#12306](https://github.com/crystal-lang/crystal/pull/12306), thanks @asterite) - Compiler: fix type descendent for union metaclass ([#12308](https://github.com/crystal-lang/crystal/pull/12308), thanks @asterite) - Compiler: fix `is_a?` from generic class against generic class instance type ([#12312](https://github.com/crystal-lang/crystal/pull/12312), thanks @asterite) - Fix `self` in restrictions when instantiating macro def in subtypes ([#10954](https://github.com/crystal-lang/crystal/pull/10954), thanks @HertzDevil) - Never resolve free variables as types during overload ordering ([#11973](https://github.com/crystal-lang/crystal/pull/11973), thanks @HertzDevil) - Use instantiated type as `self` when inferring instance variable types ([#12466](https://github.com/crystal-lang/crystal/pull/12466), thanks @HertzDevil) - Fix restriction comparison between `Metaclass` and `Path` ([#12523](https://github.com/crystal-lang/crystal/pull/12523), thanks @HertzDevil) - **(performance)** Compiler: don't always use Array for node dependencies and observers ([#12405](https://github.com/crystal-lang/crystal/pull/12405), thanks @asterite) - Compiler: better error message for symbol against enum ([#12478](https://github.com/crystal-lang/crystal/pull/12478), thanks @asterite) ### Tools #### Docs-generator - Fix docs generator search constants id ([#12262](https://github.com/crystal-lang/crystal/pull/12262), thanks @GeopJr) #### Formatter - Formatter: format comment after select ([#12506](https://github.com/crystal-lang/crystal/pull/12506), thanks @asterite) - Formatter: try to format macros that don't interpolate content ([#12378](https://github.com/crystal-lang/crystal/pull/12378), thanks @asterite) #### Playground - Playground: Fix pass bound hostname to run sessions ([#12356](https://github.com/crystal-lang/crystal/pull/12356), thanks @orangeSi) - Don't show stacktrace when playground port is already in use. ([#11844](https://github.com/crystal-lang/crystal/pull/11844), thanks @hugopl) - Indent playground code using spaces ([#12231](https://github.com/crystal-lang/crystal/pull/12231), thanks @potomak) ### Other - `bin/crystal`: Ensure `sh` compatibility ([#12486](https://github.com/crystal-lang/crystal/pull/12486), thanks @HertzDevil) - bumping version 1.6.0-dev ([#12263](https://github.com/crystal-lang/crystal/pull/12263), thanks @beta-ziliani) - updating CI to 1.5.0 ([#12260](https://github.com/crystal-lang/crystal/pull/12260), thanks @beta-ziliani) - Add fish shell completion ([#12026](https://github.com/crystal-lang/crystal/pull/12026), thanks @TunkShif) - Execute `compopt` only when it's present ([#12248](https://github.com/crystal-lang/crystal/pull/12248), thanks @potomak) - Use `Makefile.win` and wrapper script on Windows CI ([#12344](https://github.com/crystal-lang/crystal/pull/12344), thanks @HertzDevil) - [Makefile] Add format target ([#11420](https://github.com/crystal-lang/crystal/pull/11420), thanks @straight-shoota) - Update contact section of CODE of CONDUCT ([#9219](https://github.com/crystal-lang/crystal/pull/9219), thanks @paulcsmith) - Update nixpkgs 22.05 and LLVM 11 ([#12498](https://github.com/crystal-lang/crystal/pull/12498), thanks @straight-shoota) - [Makefile] Use `EXPORT_CC` for `make crystal` ([#11760](https://github.com/crystal-lang/crystal/pull/11760), thanks @straight-shoota) - Update distribution-scripts ([#12502](https://github.com/crystal-lang/crystal/pull/12502), [#12555](https://github.com/crystal-lang/crystal/pull/12555), thanks @straight-shoota) - Fix and enhance `scripts/update-distribution-scripts.sh` ([#12503](https://github.com/crystal-lang/crystal/pull/12503), thanks @straight-shoota) - [CI] Upgrade GitHub Actions to macos-11 ([#12500](https://github.com/crystal-lang/crystal/pull/12500), thanks @straight-shoota) - Add icon and metadata to Windows Crystal compiler binary ([#12494](https://github.com/crystal-lang/crystal/pull/12494), thanks @HertzDevil) - Remove `spec/win32_std_spec.cr` and `spec/generate_windows_spec.sh` ([#12282](https://github.com/crystal-lang/crystal/pull/12282), [#12549](https://github.com/crystal-lang/crystal/pull/12549), thanks @HertzDevil and @straight-shoota) ================================================ FILE: doc/changelogs/v1.7.md ================================================ # Changelog 1.7 ## [1.7.3] - 2023-03-07 [1.7.3]: https://github.com/crystal-lang/crystal/releases/1.7.3 ### Standard Library #### Text - Do not use `@[ThreadLocal]` for PCRE2's JIT stack ([#13056](https://github.com/crystal-lang/crystal/pull/13056), thanks @HertzDevil) - Fix `libpcre2` bindings with arch-dependent types (`SizeT`) ([#13088](https://github.com/crystal-lang/crystal/pull/13088), thanks @straight-shoota) - Fix `libpcre2` bindings function pointers ([#13090](https://github.com/crystal-lang/crystal/pull/13090), thanks @straight-shoota) - Fix PCRE2 do not allocate JIT stack if unavailable ([#13100](https://github.com/crystal-lang/crystal/pull/13100), thanks @straight-shoota) - Backport PCRE2 fixes to 1.7 ([#13136](https://github.com/crystal-lang/crystal/pull/13136), thanks @straight-shoota) - Fix `MatchData#[]` named capture with identical prefix ([#13147](https://github.com/crystal-lang/crystal/pull/13147), thanks @straight-shoota) - Fix `Regex::Option` behaviour for unnamed members ([#13155](https://github.com/crystal-lang/crystal/pull/13155), thanks @straight-shoota) - **(performance)** Improve PCRE2 match performance for JIT and interpreted ([#13146](https://github.com/crystal-lang/crystal/pull/13146), thanks @straight-shoota) ### Compiler #### Generics - Explicitly treat unbound type vars in generic class methods as free variables ([#13125](https://github.com/crystal-lang/crystal/pull/13125), thanks @HertzDevil) ### Other - [CI] Fix add PCRE2 to GHA cache for win job ([#13089](https://github.com/crystal-lang/crystal/pull/13089), thanks @straight-shoota) - [CI] Pin `use_pcre` in build environments where PCRE2 is not yet available ([#13102](https://github.com/crystal-lang/crystal/pull/13102), thanks @straight-shoota) ## [1.7.2] - 2023-01-23 [1.7.2]: https://github.com/crystal-lang/crystal/releases/1.7.2 ### Standard Library #### Runtime - Fix: Add `Nil` return type restrictions to `load_debug_info` ([#12992](https://github.com/crystal-lang/crystal/pull/12992), thanks @straight-shoota) ### Compiler #### Codegen - Add error handling to compiler when linker is unavailable ([#12899](https://github.com/crystal-lang/crystal/pull/12899), thanks @straight-shoota) #### Parser - Revert "Parser: Fix restrict grammar for name and supertype in type def (#12622)" ([#12977](https://github.com/crystal-lang/crystal/pull/12977), thanks @straight-shoota) ### Other - Update `VERSION` to `1.7.2-dev` ([#12993](https://github.com/crystal-lang/crystal/pull/12993), thanks @straight-shoota) ## [1.7.1] - 2023-01-17 [1.7.1]: https://github.com/crystal-lang/crystal/releases/1.7.1 ### Tools #### Playground - Fix baked-in path in playground to resolve at runtime ([#12948](https://github.com/crystal-lang/crystal/pull/12948), thanks @straight-shoota) ### Other - Update `VERSION` to 1.7.1-dev ([#12950](https://github.com/crystal-lang/crystal/pull/12950), thanks @straight-shoota) ## [1.7.0] - 2023-01-09 [1.7.0]: https://github.com/crystal-lang/crystal/releases/1.7.0 ### Language - Add lib functions earlier so that they are visible in top-level macros ([#12848](https://github.com/crystal-lang/crystal/pull/12848), thanks @asterite) ### Standard Library - Improve `Benchmark` docs ([#12782](https://github.com/crystal-lang/crystal/pull/12782), thanks @r00ster91, @straight-shoota) - Improve documentation for `Object#to_s` and `#inspect` ([#9974](https://github.com/crystal-lang/crystal/pull/9974), thanks @straight-shoota) - Add methods to manipulate semantic versions ([#12834](https://github.com/crystal-lang/crystal/pull/12834), thanks @gabriel-ss) - Add types to methods with defaults ([#12837](https://github.com/crystal-lang/crystal/pull/12837), thanks @caspiano) - examples: fix (2022-10) ([#12665](https://github.com/crystal-lang/crystal/pull/12665), thanks @maiha) - Fix documentation for `Pointer#move_to` ([#12677](https://github.com/crystal-lang/crystal/pull/12677), thanks @TheEEs) - **(performance)** Eliminate `nil` from many predicate methods ([#12702](https://github.com/crystal-lang/crystal/pull/12702), thanks @HertzDevil) - examples: fix (2022-12) ([#12870](https://github.com/crystal-lang/crystal/pull/12870), thanks @maiha) #### Collection - Fix missed elements in `Hash#select!(keys : Enumerable)` ([#12739](https://github.com/crystal-lang/crystal/pull/12739), thanks @caspiano) - Add missing docs for `Indexable` combinations methods ([#10548](https://github.com/crystal-lang/crystal/pull/10548), thanks @keidax) - **(performance)** Optimize `Range#sample(n)` for integers and floats ([#12535](https://github.com/crystal-lang/crystal/pull/12535), thanks @straight-shoota) - Add `Iterable#each_cons_pair` ([#12726](https://github.com/crystal-lang/crystal/pull/12726), thanks @caspiano) - Add links to equivalent `Iterator` methods in `Iterable` ([#12727](https://github.com/crystal-lang/crystal/pull/12727), thanks @caspiano) - **(performance)** Optimize `Hash#select(Enumerable)` and `#merge!(Hash, &)` ([#12737](https://github.com/crystal-lang/crystal/pull/12737), thanks @HertzDevil) - Add `Indexable#rindex!` method variant ([#12759](https://github.com/crystal-lang/crystal/pull/12759), thanks @Sija) - **(performance)** Use mutating collection methods ([#12644](https://github.com/crystal-lang/crystal/pull/12644), thanks @caspiano) - Fix `Enum#to_s` for flag enum containing named and unnamed members ([#12895](https://github.com/crystal-lang/crystal/pull/12895), thanks @straight-shoota) #### Concurrency - Allow the EventLoop implementation to be detected at runtime ([#12656](https://github.com/crystal-lang/crystal/pull/12656), thanks @lbguilherme) - **(performance)** Optimize uniqueness filter in `Channel.select_impl` ([#12814](https://github.com/crystal-lang/crystal/pull/12814), thanks @straight-shoota) - Implement multithreading primitives on Windows ([#11647](https://github.com/crystal-lang/crystal/pull/11647), thanks @HertzDevil) #### Crypto - **(breaking-change)** Implement `Digest` class in `Digest::CRC32` and `Digest::Adler32` ([#11535](https://github.com/crystal-lang/crystal/pull/11535), thanks @BlobCodes) - Fix `OpenSSL::SSL::Context::Client#alpn_protocol=` ([#12724](https://github.com/crystal-lang/crystal/pull/12724), thanks @jaclarke) - Fix `HTTP::Client` certificate validation error on FQDN (host with trailing dot) ([#12778](https://github.com/crystal-lang/crystal/pull/12778), thanks @compumike) - Enable `arc4random(3)` on all supported BSDs and macOS/Darwin ([#12608](https://github.com/crystal-lang/crystal/pull/12608), thanks @dmgk) #### Files - Fix: Read `UInt` in zip directory header ([#12822](https://github.com/crystal-lang/crystal/pull/12822), thanks @pbrumm) - Add `File.executable?` for Windows ([#9677](https://github.com/crystal-lang/crystal/pull/9677), thanks @nof1000) #### Macros - Fix `TypeNode#nilable?` for root types ([#12354](https://github.com/crystal-lang/crystal/pull/12354), thanks @HertzDevil) - Add argless `#annotations` overload ([#9326](https://github.com/crystal-lang/crystal/pull/9326), thanks @Blacksmoke16) - Add specs for addition between `ArrayLiteral` and `TupleLiteral` ([#12639](https://github.com/crystal-lang/crystal/pull/12639), thanks @caspiano) - Add `ArrayLiteral#-(other)` and `TupleLiteral#-(other)` ([#12646](https://github.com/crystal-lang/crystal/pull/12646), [#12916](https://github.com/crystal-lang/crystal/pull/12916) thanks @caspiano, @straight-shoota) #### Networking - **(breaking-change)** Add `HTTP::Headers#serialize` ([#12765](https://github.com/crystal-lang/crystal/pull/12765), thanks @straight-shoota) - Ensure `HTTP::Client` closes response when breaking out of block ([#12749](https://github.com/crystal-lang/crystal/pull/12749), thanks @straight-shoota) - Add `HTTP::Server::Response#redirect` ([#12526](https://github.com/crystal-lang/crystal/pull/12526), thanks @straight-shoota) - **(performance)** Websocket: write masked data to temporary buffer before sending it ([#12613](https://github.com/crystal-lang/crystal/pull/12613), thanks @asterite) - Validate cookie name prefixes ([#10648](https://github.com/crystal-lang/crystal/pull/10648), thanks @Blacksmoke16) - `IPAddress#loopback?` should consider `::ffff:127.0.0.1/104` loopback too ([#12783](https://github.com/crystal-lang/crystal/pull/12783), thanks @carlhoerberg) #### Numeric - Support new SI prefixes in `Number#humanize` ([#12761](https://github.com/crystal-lang/crystal/pull/12761), thanks @HertzDevil) - Fix `BigInt#%` for unsigned integers ([#12773](https://github.com/crystal-lang/crystal/pull/12773), thanks @straight-shoota) - [WASM] Add missing `__powisf2` and `__powidf2` compiler-rt functions ([#12569](https://github.com/crystal-lang/crystal/pull/12569), thanks @lbguilherme) - Add docs for `Int#downto` ([#12468](https://github.com/crystal-lang/crystal/pull/12468), thanks @yb66) - Upgrade the Dragonbox algorithm ([#12767](https://github.com/crystal-lang/crystal/pull/12767), thanks @HertzDevil) - Support scientific notation in `BigDecimal#to_s` ([#10805](https://github.com/crystal-lang/crystal/pull/10805), thanks @HertzDevil) - Add `#bit_reverse` and `#byte_swap` for primitive integers ([#12865](https://github.com/crystal-lang/crystal/pull/12865), thanks @HertzDevil) - Fix Number comparison operator docs ([#12880](https://github.com/crystal-lang/crystal/pull/12880), thanks @fdocr) #### Runtime - `Exception::CallStack`: avoid allocations in `LibC.dl_iterate_phdr` ([#12625](https://github.com/crystal-lang/crystal/pull/12625), thanks @dmgk) - Fix explicit type conversion to u64 for `GC::Stats` ([#12779](https://github.com/crystal-lang/crystal/pull/12779), thanks @straight-shoota) - Add custom `message` parameter to `#not_nil!` ([#12797](https://github.com/crystal-lang/crystal/pull/12797), thanks @straight-shoota) - Refactor specs for `Enum#to_s` using `assert_prints` ([#12882](https://github.com/crystal-lang/crystal/pull/12882), thanks @straight-shoota) #### Serialization - **(performance)** Leverage `GC.malloc_atomic` for XML ([#12692](https://github.com/crystal-lang/crystal/pull/12692), thanks @HertzDevil) - Refactor libXML error handling to remove global state ([#12663](https://github.com/crystal-lang/crystal/pull/12663), [#12795](https://github.com/crystal-lang/crystal/pull/12795), thanks @straight-shoota) - Use qualified type reference `YAML::Any` ([#12688](https://github.com/crystal-lang/crystal/pull/12688), thanks @zw963) - Automatically cast Int to Float for `{JSON,YAML}::Any#as_f` ([#12835](https://github.com/crystal-lang/crystal/pull/12835), thanks @compumike) #### Specs - Print seed info at start and end of spec output ([#12755](https://github.com/crystal-lang/crystal/pull/12755), thanks @straight-shoota) #### System - **(breaking)** Rename `File.real_path` to `.realpath` ([#12552](https://github.com/crystal-lang/crystal/pull/12552), thanks @straight-shoota) - **(breaking-change)** Drop FreeBSD 11 compatibility code ([#12612](https://github.com/crystal-lang/crystal/pull/12612), thanks @dmgk) - Trap when trying to raise wasm32 exceptions ([#12572](https://github.com/crystal-lang/crystal/pull/12572), thanks @lbguilherme) - Use single helper method to pass UTF-16 strings to Windows ([#12695](https://github.com/crystal-lang/crystal/pull/12695), [#12747](https://github.com/crystal-lang/crystal/pull/12747), thanks @HertzDevil, @straight-shoota) - Implement `flock_*` fiber-aware, without blocking the thread ([#12861](https://github.com/crystal-lang/crystal/pull/12861), [#12728](https://github.com/crystal-lang/crystal/pull/12728), thanks @straight-shoota) - Implement `flock_*` for Win32 ([#12766](https://github.com/crystal-lang/crystal/pull/12766), thanks @straight-shoota) - Add docs to `ENV#has_key?` ([#12781](https://github.com/crystal-lang/crystal/pull/12781), thanks @straight-shoota) - Improve specs by removing absolute path references ([#12776](https://github.com/crystal-lang/crystal/pull/12776), thanks @straight-shoota) - Update FreeBSD LibC types ([#12651](https://github.com/crystal-lang/crystal/pull/12651), thanks @dmgk) - Organize `Process` specs ([#12889](https://github.com/crystal-lang/crystal/pull/12889), thanks @straight-shoota) - Add tests for `Process::Status` ([#12881](https://github.com/crystal-lang/crystal/pull/12881), thanks @straight-shoota) #### Text - Raise `IndexError` on unmatched subpattern for `MatchData#begin` and `#end` ([#12810](https://github.com/crystal-lang/crystal/pull/12810), thanks @straight-shoota) - Swap documentation for `String#split` array and block versions ([#12808](https://github.com/crystal-lang/crystal/pull/12808), thanks @hugopl) - Add `String#index/rindex!` methods ([#12730](https://github.com/crystal-lang/crystal/pull/12730), thanks @Sija) - Re-organize and enhance specs for `Regex` and `Regex::MatchData` ([#12788](https://github.com/crystal-lang/crystal/pull/12788), [#12789](https://github.com/crystal-lang/crystal/pull/12789), thanks @straight-shoota) - Add missing positive spec for `Regex#match` with option ([#12804](https://github.com/crystal-lang/crystal/pull/12804), thanks @straight-shoota) - Replace `if !blank?` with `unless blank?` ([#12800](https://github.com/crystal-lang/crystal/pull/12800), thanks @vlazar) - Add references between String equality, comparison methods ([#10531](https://github.com/crystal-lang/crystal/pull/10531), thanks @straight-shoota) - Extract internal Regex API for PCRE backend ([#12802](https://github.com/crystal-lang/crystal/pull/12802), thanks @straight-shoota) - Implement `Regex` engine on PCRE2 ([#12856](https://github.com/crystal-lang/crystal/pull/12856), [#12866](https://github.com/crystal-lang/crystal/pull/12866), [#12847](https://github.com/crystal-lang/crystal/pull/12847), thanks @straight-shoota, thanks @HertzDevil) - Add missing overloads for `String#byte_slice` ([#12809](https://github.com/crystal-lang/crystal/pull/12809), thanks @straight-shoota) ### Compiler - Improve error message when there are extra types ([#12734](https://github.com/crystal-lang/crystal/pull/12734), thanks @asterite) - Handle triples without libc ([#12594](https://github.com/crystal-lang/crystal/pull/12594), thanks @GeopJr) - Remove unused `Program#cache_dir` property ([#12669](https://github.com/crystal-lang/crystal/pull/12669), thanks @straight-shoota) - Fix: Unwrap nested errors in error handler for `Crystal::Error` ([#12888](https://github.com/crystal-lang/crystal/pull/12888), thanks @straight-shoota) #### Codegen - Add missing specs for `->var.foo` semantics with assignments ([#9419](https://github.com/crystal-lang/crystal/pull/9419), thanks @makenowjust) - Use `File#flock_exclusive` on win32 in compiler ([#12876](https://github.com/crystal-lang/crystal/pull/12876), thanks @straight-shoota) #### Generics - Redefine defs when constant and number in generic arguments are equal ([#12785](https://github.com/crystal-lang/crystal/pull/12785), thanks @HertzDevil) - Fix restriction of numeral generic argument against non-free variable `Path` ([#12784](https://github.com/crystal-lang/crystal/pull/12784), thanks @HertzDevil) #### Interpreter - Interpreter: fix class var initializer that needs an upcast ([#12635](https://github.com/crystal-lang/crystal/pull/12635), thanks @asterite) - Reverting #12405 Compiler: don't always use Array for node dependencies and observers ([#12849](https://github.com/crystal-lang/crystal/pull/12849), thanks @beta-ziliani) - Match Nix loader errors in compiler spec ([#12852](https://github.com/crystal-lang/crystal/pull/12852), thanks @bcardiff) - Interpreter reply ([#12738](https://github.com/crystal-lang/crystal/pull/12738), thanks @I3oris) #### Parser - **(breaking-change)** Parser: Fix restrict grammar for name and supertype in type def ([#12622](https://github.com/crystal-lang/crystal/pull/12622), thanks @caspiano) - Lexer: fix global capture vars ending with zero, e.g. `$10?` ([#12701](https://github.com/crystal-lang/crystal/pull/12701), thanks @FnControlOption) - Lexer: allow regex after CRLF ([#12713](https://github.com/crystal-lang/crystal/pull/12713), thanks @FnControlOption) - Assignment to global regex match data is not allowed ([#12714](https://github.com/crystal-lang/crystal/pull/12714), thanks @caspiano) - Error when declaring a constant within another constant declaration ([#12566](https://github.com/crystal-lang/crystal/pull/12566), thanks @caspiano) - Fix calls with do-end blocks within index operators ([#12824](https://github.com/crystal-lang/crystal/pull/12824), thanks @caspiano) - Remove oct/bin floating point literals ([#12687](https://github.com/crystal-lang/crystal/pull/12687), thanks @BlobCodes) - Parser: fix wrong/missing locations of various AST nodes ([#11798](https://github.com/crystal-lang/crystal/pull/11798), thanks @FnControlOption) - Refactor: use helper method instead of duplicate code in lexer ([#12590](https://github.com/crystal-lang/crystal/pull/12590), thanks @straight-shoota) - Simplify sequential character checks in Crystal lexer ([#12699](https://github.com/crystal-lang/crystal/pull/12699), thanks @caspiano) - Lexer: delete redundant `scan_ident` calls ([#12691](https://github.com/crystal-lang/crystal/pull/12691), thanks @FnControlOption) - Rename `Def#yields` to `Def#block_arity` ([#12833](https://github.com/crystal-lang/crystal/pull/12833), thanks @straight-shoota) - Fix warning on space before colon with anonymous block arg ([#12869](https://github.com/crystal-lang/crystal/pull/12869), thanks @straight-shoota) - Warn on missing space before colon in type declaration/restriction ([#12740](https://github.com/crystal-lang/crystal/pull/12740), thanks @straight-shoota) #### Semantic - Fix: Do not merge union types in truthy filter ([#12752](https://github.com/crystal-lang/crystal/pull/12752), thanks @straight-shoota) - Fix crash when using `sizeof`, `instance_sizeof`, or `offsetof` as a type arg ([#12577](https://github.com/crystal-lang/crystal/pull/12577), thanks @keidax) - Resolve type of free variable on block return type mismatch ([#12754](https://github.com/crystal-lang/crystal/pull/12754), thanks @caspiano) - Order `_` after any other `Path` when comparing overloads ([#12855](https://github.com/crystal-lang/crystal/pull/12855), thanks @HertzDevil) - [Experimental] Compiler: try to solve string interpolation exps at compile time ([#12524](https://github.com/crystal-lang/crystal/pull/12524), thanks @asterite) - Support `@[Deprecated]` on `annotation` ([#12557](https://github.com/crystal-lang/crystal/pull/12557), thanks @caspiano) - Add more specific error message for uninstantiated proc type ([#11219](https://github.com/crystal-lang/crystal/pull/11219), thanks @straight-shoota) - Add specs for `system` macro method ([#12885](https://github.com/crystal-lang/crystal/pull/12885), thanks @straight-shoota) ### Tools #### Docs-generator - Fix range literals causing method lookups in docs generator ([#12680](https://github.com/crystal-lang/crystal/pull/12680), thanks @caspiano) - Fix method lookup for single char class names ([#12683](https://github.com/crystal-lang/crystal/pull/12683), thanks @caspiano) #### Formatter - Formatter: document stdin filename argument (`-`) ([#12620](https://github.com/crystal-lang/crystal/pull/12620), thanks @caspiano) ### Other #### Infrastructure - [CI] Drop Alpine libreSSL 3.1 test ([#12641](https://github.com/crystal-lang/crystal/pull/12641), thanks @straight-shoota) - Bump version to 1.7.0-dev ([#12640](https://github.com/crystal-lang/crystal/pull/12640), thanks @straight-shoota) - [CI] Update GHA actions ([#12501](https://github.com/crystal-lang/crystal/pull/12501), thanks @straight-shoota) - Opt in to new overload ordering behavior in Makefile ([#12703](https://github.com/crystal-lang/crystal/pull/12703), thanks @HertzDevil) - Merge release 1.6.2 into master ([#12719](https://github.com/crystal-lang/crystal/pull/12719), thanks @beta-ziliani) - Configure Renovate ([#12678](https://github.com/crystal-lang/crystal/pull/12678), thanks @renovate) - [CI] Add version pin for ilammy/msvc-dev-cmd in windows CI ([#12746](https://github.com/crystal-lang/crystal/pull/12746), thanks @straight-shoota) - [CI] Update dependencies for windows CI ([#12745](https://github.com/crystal-lang/crystal/pull/12745), thanks @straight-shoota) - Update GH Actions ([#12742](https://github.com/crystal-lang/crystal/pull/12742), thanks @renovate) - [CI] Run specs in random order by default ([#12541](https://github.com/crystal-lang/crystal/pull/12541), thanks @straight-shoota) - Update `shell.nix` for newer LLVM versions and aarch64-darwin ([#12591](https://github.com/crystal-lang/crystal/pull/12591), thanks @HertzDevil) - Update previous Crystal release - 1.6.2 ([#12750](https://github.com/crystal-lang/crystal/pull/12750), thanks @straight-shoota) - [CI] Update PCRE 8.45 for Windows CI ([#12762](https://github.com/crystal-lang/crystal/pull/12762), thanks @HertzDevil) - Add WebAssembly specs ([#12571](https://github.com/crystal-lang/crystal/pull/12571), thanks @lbguilherme) - Update actions/checkout action to v3 ([#12805](https://github.com/crystal-lang/crystal/pull/12805), thanks @renovate) - Enable multithreading specs on Windows CI ([#12843](https://github.com/crystal-lang/crystal/pull/12843), thanks @HertzDevil) - [CI] Update mwilliamson/setup-wasmtime-action action to v2 ([#12864](https://github.com/crystal-lang/crystal/pull/12864), thanks @renovate) - [CI] Update distribution-scripts ([#12891](https://github.com/crystal-lang/crystal/pull/12891), thanks @straight-shoota) - [CI] Update shards 0.17.2 ([#12875](https://github.com/crystal-lang/crystal/pull/12875), thanks @straight-shoota) - Rotate breached credentials in CircleCI ([#12902](https://github.com/crystal-lang/crystal/pull/12902), thanks @matiasgarciaisaia) - Update `NOTICE.md` ([#12901](https://github.com/crystal-lang/crystal/pull/12901), thanks @HertzDevil) - Split pre-1.0 changelog ([#12898](https://github.com/crystal-lang/crystal/pull/12898), thanks @straight-shoota) #### Code Improvements - Style: Remove redundant begin blocks ([#12638](https://github.com/crystal-lang/crystal/pull/12638), thanks @caspiano) - Lint: Fix variable name casing ([#12674](https://github.com/crystal-lang/crystal/pull/12674), thanks @Sija) - Lint: Remove comparisons with boolean literals ([#12673](https://github.com/crystal-lang/crystal/pull/12673), thanks @Sija) - Lint: Use `Object#in?` instead of multiple comparisons ([#12675](https://github.com/crystal-lang/crystal/pull/12675), thanks @Sija) - Lint: Remove useless assignments ([#12648](https://github.com/crystal-lang/crystal/pull/12648), thanks @Sija) - Use `Object#in?` in place of multiple comparisons ([#12700](https://github.com/crystal-lang/crystal/pull/12700), thanks @caspiano) - Style: Remove explicit returns from the codebase ([#12637](https://github.com/crystal-lang/crystal/pull/12637), thanks @caspiano) - Lint: Use `Enumerable#find!/#index!` variants ([#12686](https://github.com/crystal-lang/crystal/pull/12686), thanks @Sija) - Style: Use short block notation for simple one-liners ([#12676](https://github.com/crystal-lang/crystal/pull/12676), thanks @Sija) - Couple of ameba lint issues fixed ([#12685](https://github.com/crystal-lang/crystal/pull/12685), thanks @Sija) - Use context-specific heredoc deliminators ([#12816](https://github.com/crystal-lang/crystal/pull/12816), thanks @straight-shoota) ================================================ FILE: doc/changelogs/v1.8.md ================================================ # Changelog 1.8 ## [1.8.2] - 2023-05-08 [1.8.2]: https://github.com/crystal-lang/crystal/releases/1.8.2 ### Standard Library #### Collection - Fix codegen bug with `Iterator::ChainIterator` ([#13412](https://github.com/crystal-lang/crystal/pull/13412), thanks @straight-shoota) #### Log - Fix `Log::Metadata#dup` crash with 2+ entries ([#13369](https://github.com/crystal-lang/crystal/pull/13369), thanks @HertzDevil) #### Serialization - Fixup for `JSON::Serializable` on certain recursively defined types ([#13430](https://github.com/crystal-lang/crystal/pull/13430), thanks @kostya) #### Text - Fix `String#scan` with empty `Regex` match at multibyte char ([#13387](https://github.com/crystal-lang/crystal/pull/13387), thanks @HertzDevil) - **(performance)** Check subject UTF-8 validity just once for `String#gsub`, `#scan`, `#split` ([#13406](https://github.com/crystal-lang/crystal/pull/13406), thanks @HertzDevil) ### Compiler #### Codegen - Always use 0 for offset of `StaticArray`'s `@buffer` ([#13319](https://github.com/crystal-lang/crystal/pull/13319), thanks @HertzDevil) ### Other - Backport bugfixes to release/1.8 for release 1.8.2 ([#3435](https://github.com/crystal-lang/crystal/pull/13435), thanks @straight-shoota) ## [1.8.1] - 2023-04-20 [1.8.1]: https://github.com/crystal-lang/crystal/releases/1.8.1 ### Standard Library #### Serialization - Fix `JSON::Serializable` on certain recursively defined types ([#13344](https://github.com/crystal-lang/crystal/pull/13344), thanks @HertzDevil) #### Text - Fix `String#gsub` with empty match at multibyte char ([#13342](https://github.com/crystal-lang/crystal/pull/13342), thanks @straight-shoota) - Fix PCRE2 `Regex` with more than 127 named capture groups ([#13349](https://github.com/crystal-lang/crystal/pull/13349), thanks @HertzDevil) ## [1.8.0] - 2023-04-14 [1.8.0]: https://github.com/crystal-lang/crystal/releases/1.8.0 ### Language - The compiler uses PCRE2 to validate regex literals ([#13084](https://github.com/crystal-lang/crystal/pull/13084), thanks @straight-shoota) - Fill docs for `TupleLiteral` ([#12927](https://github.com/crystal-lang/crystal/pull/12927), thanks @straight-shoota) - Allow namespaced `Path`s as type names for `lib` ([#12903](https://github.com/crystal-lang/crystal/pull/12903), thanks @HertzDevil) ### Standard Library - Fix `SyntaxHighlighter::HTML` to escape identifier values ([#13212](https://github.com/crystal-lang/crystal/pull/13212), thanks @straight-shoota) - Add workaround for `Value#not_nil!` copying the receiver ([#13264](https://github.com/crystal-lang/crystal/pull/13264), thanks @HertzDevil) - Fix `Pointer#copy_to` overflow on unsigned size and different target type ([#13269](https://github.com/crystal-lang/crystal/pull/13269), thanks @HertzDevil) - Docs: Added note about imports where necessary ([#13026](https://github.com/crystal-lang/crystal/pull/13026), [#13066](https://github.com/crystal-lang/crystal/pull/13066), thanks @Tamnac, @straight-shoota) - Suppress compiler output in `compile_file` spec helper ([#13228](https://github.com/crystal-lang/crystal/pull/13228), thanks @straight-shoota) - Define equality for `Process::Status` and `OAuth::RequestToken` ([#13014](https://github.com/crystal-lang/crystal/pull/13014), thanks @HertzDevil) - Fix some Linux glibc bindings ([#13242](https://github.com/crystal-lang/crystal/pull/13242), [#13249](https://github.com/crystal-lang/crystal/pull/13249), thanks @ysbaddaden, @HertzDevil) #### Collection - **(breaking-change)** Fix `Enum#includes?` to require all bits set ([#13229](https://github.com/crystal-lang/crystal/pull/13229), thanks @straight-shoota) - **(breaking-change)** Deprecate `Enum.flags` ([#12900](https://github.com/crystal-lang/crystal/pull/12900), thanks @straight-shoota) - **(breaking-change)** Remove compile-time error for `Range#size`, `#each`, `#sample` ([#13278](https://github.com/crystal-lang/crystal/pull/13278), thanks @straight-shoota) - **(breaking-change)** Docs: Require all `Indexable`s to be stable ([#13061](https://github.com/crystal-lang/crystal/pull/13061), thanks @HertzDevil) - Add `Enum.[]` convenience constructor ([#12900](https://github.com/crystal-lang/crystal/pull/12900), thanks @straight-shoota) - Rename internal `Iterator::Slice` type to not conflict with `::Slice` ([#12983](https://github.com/crystal-lang/crystal/pull/12983), thanks @Blacksmoke16) - Fix `Array#replace` on shifted arrays ([#13256](https://github.com/crystal-lang/crystal/pull/13256), thanks @HertzDevil) - Add `Tuple#to_static_array` ([#12930](https://github.com/crystal-lang/crystal/pull/12930), thanks @straight-shoota) - Add `Enum#inspect` ([#13004](https://github.com/crystal-lang/crystal/pull/13004), thanks @straight-shoota) - Add `Slice#+(Slice)` and `Slice.join` ([#12081](https://github.com/crystal-lang/crystal/pull/12081), thanks @HertzDevil) - Add `Enumerable#min(count)` and `#max(count)` ([#13057](https://github.com/crystal-lang/crystal/pull/13057), thanks @nthiad) - Fix `Array(T)#[]=(Int, Int, Array(T))` on shifted arrays ([#13275](https://github.com/crystal-lang/crystal/pull/13275), thanks @HertzDevil) #### Concurrency - Fix: Make sure to dup `Array` in `Channel.select_impl` ([#12827](https://github.com/crystal-lang/crystal/pull/12827), [#12962](https://github.com/crystal-lang/crystal/pull/12962), thanks @straight-shoota) - Add memory barriers on lock/unlock of SpinLock ([#13050](https://github.com/crystal-lang/crystal/pull/13050), thanks @bcardiff) - **(performance)** Avoid `Array` allocation in `Channel.select(Tuple)` ([#12960](https://github.com/crystal-lang/crystal/pull/12960), thanks @straight-shoota) #### Files - **(breaking-change)** Deprecate `Termios` ([#12940](https://github.com/crystal-lang/crystal/pull/12940), thanks @HertzDevil) - **(breaking-change)** Windows: make `File.delete` remove symlink directories, not `Dir.delete` ([#13224](https://github.com/crystal-lang/crystal/pull/13224), thanks @HertzDevil) - Leverage `fileapi` for opening files on windows ([#13178](https://github.com/crystal-lang/crystal/pull/13178), thanks @Blacksmoke16) - Windows: fix error condition when `File.open` fails ([#13235](https://github.com/crystal-lang/crystal/pull/13235), thanks @HertzDevil) - Skip eacces spec for superuser ([#13227](https://github.com/crystal-lang/crystal/pull/13227), thanks @straight-shoota) - Improve `File.symlink` on Windows ([#13141](https://github.com/crystal-lang/crystal/pull/13141), thanks @HertzDevil) - Implement `File.readlink` on Windows ([#13195](https://github.com/crystal-lang/crystal/pull/13195), thanks @HertzDevil) #### LLVM - **(breaking-change)** Drop support for LLVM < 8 ([#12906](https://github.com/crystal-lang/crystal/pull/12906), thanks @straight-shoota) - **(breaking-change)** Support LLVM 15 ([#13173](https://github.com/crystal-lang/crystal/pull/13173), thanks @HertzDevil) - Error when `find-llvm-config` is unsuccessful ([#13045](https://github.com/crystal-lang/crystal/pull/13045), thanks @straight-shoota) - Remove `LibLLVM.has_constant?(:AttributeRef)` checks ([#13162](https://github.com/crystal-lang/crystal/pull/13162), thanks @HertzDevil) - Refactor `LLVM::Attribute#each_kind` to use `Enum#each` ([#13234](https://github.com/crystal-lang/crystal/pull/13234), thanks @straight-shoota) #### Networking - Fix socket specs when network not available ([#12961](https://github.com/crystal-lang/crystal/pull/12961), thanks @straight-shoota) - Fix wrong default address when binding sockets ([#13006](https://github.com/crystal-lang/crystal/pull/13006), thanks @etra0) - Clarify WebSocket documentation ([#13096](https://github.com/crystal-lang/crystal/pull/13096), thanks @j8r) - Add `Socket::IPAddress#link_local?` ([#13204](https://github.com/crystal-lang/crystal/pull/13204), thanks @GeopJr) - Clean up `back\slash.txt` in `HTTP::StaticFileHandler` specs ([#12984](https://github.com/crystal-lang/crystal/pull/12984), thanks @HertzDevil) - Add `MIME::Multipart.parse(HTTP::Client::Response, &)` ([#12890](https://github.com/crystal-lang/crystal/pull/12890), thanks @straight-shoota) - Replace `LibC.ntohs` and `htons` with native code ([#13027](https://github.com/crystal-lang/crystal/pull/13027), thanks @HertzDevil) - Add `OAuth2::Client#make_token_request` returning HTTP response ([#12921](https://github.com/crystal-lang/crystal/pull/12921), thanks @cyangle) - Use exhaustive case in `HTTP::WebSocket#run` ([#13097](https://github.com/crystal-lang/crystal/pull/13097), thanks @j8r) - Increase time drift for `HTTP::StaticFileHandler`'s gzip check ([#13138](https://github.com/crystal-lang/crystal/pull/13138), thanks @HertzDevil) - OpenSSL: use Windows' system root certificate store ([#13187](https://github.com/crystal-lang/crystal/pull/13187), thanks @HertzDevil) - Handle `Range` requests in `HTTP::StaticFileHandler` ([#12886](https://github.com/crystal-lang/crystal/pull/12886), thanks @jgaskins, @straight-shoota) - Skip hostname spec if `hostname` command fails ([#12987](https://github.com/crystal-lang/crystal/pull/12987), thanks @Blacksmoke16) - Fix `Socket#tty?` to `false` on Windows ([#13175](https://github.com/crystal-lang/crystal/pull/13175), thanks @Blacksmoke16) - Fix `HTTP::Server::Response#reset` for `status_message` ([#13282](https://github.com/crystal-lang/crystal/pull/13282), thanks @straight-shoota) #### Numeric - Define `Math.pw2ceil` for all integer types ([#13127](https://github.com/crystal-lang/crystal/pull/13127), thanks @HertzDevil) - Workaround for more `Int128`-and-float methods on Windows with LLVM 14+ ([#13218](https://github.com/crystal-lang/crystal/pull/13218), thanks @HertzDevil) - Fix `Int128`-and-float conversion overflow checks on Windows LLVM 14+ ([#13222](https://github.com/crystal-lang/crystal/pull/13222), thanks @HertzDevil) - Add `Char.to_i128` and `.to_u128` ([#12958](https://github.com/crystal-lang/crystal/pull/12958), thanks @meatball133) - Docs: Add references to `Number` collection convenience constructors ([#13020](https://github.com/crystal-lang/crystal/pull/13020), thanks @straight-shoota) - Docs: Fix examples for `#byte_swap` with different int types ([#13154](https://github.com/crystal-lang/crystal/pull/13154), [#13180](https://github.com/crystal-lang/crystal/pull/13180), thanks @pan, @Blacksmoke16) - Make `BigRational.new(BigFloat)` exact ([#13295](https://github.com/crystal-lang/crystal/pull/13295), thanks @HertzDevil) #### Runtime - Increase timeout for slow specs ([#13043](https://github.com/crystal-lang/crystal/pull/13043), thanks @straight-shoota) - Use `Crystal::System.print_error` instead of `LibC.printf` ([#13161](https://github.com/crystal-lang/crystal/pull/13161), thanks @HertzDevil) - Windows: detect stack overflows on non-main `Fiber`s ([#13220](https://github.com/crystal-lang/crystal/pull/13220), thanks @HertzDevil) - Add missing require for `Crystal::ThreadLocalValue` ([#13092](https://github.com/crystal-lang/crystal/pull/13092), thanks @Sija) #### Serialization - Remove obsolete error handling in `XPathContext` ([#13038](https://github.com/crystal-lang/crystal/pull/13038), thanks @straight-shoota) - Fix JSON, YAML `use_*_discriminator` for recursive `Serializable::Strict` types ([#13238](https://github.com/crystal-lang/crystal/pull/13238), thanks @HertzDevil) - Add more specs for `YAML::Any#[]` and `#[]?` ([#11646](https://github.com/crystal-lang/crystal/pull/11646), thanks @straight-shoota) - Add `from_json` for 128-bit integers ([#13041](https://github.com/crystal-lang/crystal/pull/13041), thanks @straight-shoota) - Reduce JSON, YAML serializable test types ([#13042](https://github.com/crystal-lang/crystal/pull/13042), thanks @straight-shoota) #### Specs - Format spec results with pretty inspect ([#11635](https://github.com/crystal-lang/crystal/pull/11635), thanks @JamesGood626) - Spec: Add `--color` option to spec runner ([#12932](https://github.com/crystal-lang/crystal/pull/12932), thanks @straight-shoota) - Add `Spec::Item#all_tags` ([#12915](https://github.com/crystal-lang/crystal/pull/12915), thanks @compumike) #### System - **(breaking-change)** Add full stub for Windows signals ([#13131](https://github.com/crystal-lang/crystal/pull/13131), thanks @HertzDevil) - **(breaking-change)** Deprecate and internalize `Process.fork` ([#12934](https://github.com/crystal-lang/crystal/pull/12934), thanks @straight-shoota) - Fix `Process` spec to wait on started processes ([#12941](https://github.com/crystal-lang/crystal/pull/12941), thanks @straight-shoota) - Drop privileges in chroot spec ([#13226](https://github.com/crystal-lang/crystal/pull/13226), thanks @straight-shoota) - Drop deprecated `from_winerror` overload for `flock_*` ([#13039](https://github.com/crystal-lang/crystal/pull/13039), thanks @HertzDevil) - Add `Process.on_interrupt` ([#13034](https://github.com/crystal-lang/crystal/pull/13034), thanks @HertzDevil) - Add `Process::Status#to_s` and `#inspect` ([#13044](https://github.com/crystal-lang/crystal/pull/13044), thanks @straight-shoota) - Add `graceful` parameter to `Process#terminate` ([#13070](https://github.com/crystal-lang/crystal/pull/13070), thanks @HertzDevil) - Add `Process::ExitReason` and `Process::Status#exit_reason` ([#13052](https://github.com/crystal-lang/crystal/pull/13052), thanks @HertzDevil) - Implement `File.tempfile` in Crystal ([#12111](https://github.com/crystal-lang/crystal/pull/12111), thanks @straight-shoota) - `System::User#name`: Fall back to `#username` if unavailable ([#13137](https://github.com/crystal-lang/crystal/pull/13137), thanks @HertzDevil) - Implement `Process.ppid` on Windows ([#13140](https://github.com/crystal-lang/crystal/pull/13140), thanks @HertzDevil) - AArch64 Android support ([#13065](https://github.com/crystal-lang/crystal/pull/13065), thanks @HertzDevil) - Windows 7 support ([#11505](https://github.com/crystal-lang/crystal/pull/11505), thanks @konovod) #### Text - **(breaking-change)** Fix PCRE crashing on invalid UTF-8 ([#13240](https://github.com/crystal-lang/crystal/pull/13240), [#13311](https://github.com/crystal-lang/crystal/pull/13311), [#13313](https://github.com/crystal-lang/crystal/pull/13313), thanks @straight-shoota) - **(breaking-change)** Switch default regex engine to PCRE2 ([#12978](https://github.com/crystal-lang/crystal/pull/12978), thanks @straight-shoota) - **(breaking-change)** Add more members to `Regex::Options` ([#13223](https://github.com/crystal-lang/crystal/pull/13223), thanks @straight-shoota) - **(breaking-change)** Add `Regex::MatchOptions` ([#13248](https://github.com/crystal-lang/crystal/pull/13248), thanks @straight-shoota) - Fix PCRE2 implementation and tests ([#13105](https://github.com/crystal-lang/crystal/pull/13105), thanks @straight-shoota) - Remove pending spec for `Path#drive` with IPv6 UNC host names ([#13190](https://github.com/crystal-lang/crystal/pull/13190), thanks @HertzDevil) - Remove `Regex::PCRE2#finalize` redefinition ([#13309](https://github.com/crystal-lang/crystal/pull/13309), thanks @HertzDevil) - Clarify behavior of strings with invalid UTF-8 byte sequences ([#13314](https://github.com/crystal-lang/crystal/pull/13314), thanks @HertzDevil) - Refer to PCRE2 in `Regex`'s summary ([#13318](https://github.com/crystal-lang/crystal/pull/13318), thanks @HertzDevil) ### Compiler - Escape filenames when running `crystal spec` with multiple files ([#12929](https://github.com/crystal-lang/crystal/pull/12929), thanks @HertzDevil) - Handle ARM64 MSVC paths when cross-compiling on Windows ([#13073](https://github.com/crystal-lang/crystal/pull/13073), thanks @HertzDevil) - Use relative paths to vendored shards" ([#13315](https://github.com/crystal-lang/crystal/pull/13315), thanks @straight-shoota) #### Debugger - Always use 0 for offsets of lib / extern union members ([#13305](https://github.com/crystal-lang/crystal/pull/13305), thanks @HertzDevil) #### Codegen - **(breaking-change)** Support LLVM 15 ([#13173](https://github.com/crystal-lang/crystal/pull/13173), thanks @HertzDevil) - Remove obsolete functions from `llvm_ext.cc` ([#13177](https://github.com/crystal-lang/crystal/pull/13177), thanks @HertzDevil) #### Generics - Fix type names for generic instances with empty splat type vars ([#13189](https://github.com/crystal-lang/crystal/pull/13189), thanks @HertzDevil) #### Interpreter - Fix: Interpreter `value_to_bool` for module, generic module and generic module metaclass ([#12920](https://github.com/crystal-lang/crystal/pull/12920), thanks @asterite) - Fix redundant cast in interpreter ([#12996](https://github.com/crystal-lang/crystal/pull/12996), thanks @asterite) - Dynamic library loader: search in `-L` directories before default ones ([#13069](https://github.com/crystal-lang/crystal/pull/13069), thanks @HertzDevil) - Simplify expectation of loader spec error messages ([#12858](https://github.com/crystal-lang/crystal/pull/12858), thanks @straight-shoota) - Add support for 128-bit literals in the interpreter ([#12859](https://github.com/crystal-lang/crystal/pull/12859), thanks @straight-shoota) - Fix interpreter `value_to_bool` for `NoReturn` ([#13290](https://github.com/crystal-lang/crystal/pull/13290), thanks @straight-shoota) #### Parser - Fix `x @y` and `x @@y` in def parameters when `y` is reserved ([#12922](https://github.com/crystal-lang/crystal/pull/12922), thanks @HertzDevil) - Disallow empty exponents in number literals ([#12910](https://github.com/crystal-lang/crystal/pull/12910), thanks @HertzDevil) - Stricter checks for multiple assignment syntax ([#12919](https://github.com/crystal-lang/crystal/pull/12919), thanks @HertzDevil) #### Semantic - Compiler: type declaration with initial value gets the value's type ([#13025](https://github.com/crystal-lang/crystal/pull/13025), thanks @asterite) - Stricter checks for enum definitions ([#12945](https://github.com/crystal-lang/crystal/pull/12945), thanks @HertzDevil) - Fix error handling in macro system method when execution fails ([#12893](https://github.com/crystal-lang/crystal/pull/12893), thanks @straight-shoota) - Add comment for `LiteralExpander` `select` ([#12926](https://github.com/crystal-lang/crystal/pull/12926), thanks @straight-shoota) - Improve locations of some AST nodes ([#12933](https://github.com/crystal-lang/crystal/pull/12933), thanks @straight-shoota) - Refactor `SemanticVisitor` tighter `rescue` scope in `Require` visitor ([#12887](https://github.com/crystal-lang/crystal/pull/12887), thanks @straight-shoota) - Add specs for regex literal expansion ([#13253](https://github.com/crystal-lang/crystal/pull/13253), thanks @straight-shoota) ### Tools - Fix Crystal tool cursor parsing for filenames containing `:` ([#13129](https://github.com/crystal-lang/crystal/pull/13129), thanks @HertzDevil) #### Formatter - Formatter: fix end indent after comment inside begin ([#12994](https://github.com/crystal-lang/crystal/pull/12994), thanks @asterite) - Parser: remove obsolete handling of `else` inside lib struct ([#13028](https://github.com/crystal-lang/crystal/pull/13028), thanks @HertzDevil) - Fix formatter empty array literal with comment on extra line ([#12907](https://github.com/crystal-lang/crystal/pull/12907), thanks @straight-shoota) - Fix formatter comment on extra line at end of method args ([#12908](https://github.com/crystal-lang/crystal/pull/12908), thanks @straight-shoota) - Fix formatter not merge consecutive but separated comment lines ([#12909](https://github.com/crystal-lang/crystal/pull/12909), thanks @straight-shoota) - Formatter: add `(&)` to param-less yielding defs before comment line ([#13126](https://github.com/crystal-lang/crystal/pull/13126), thanks @HertzDevil) - Formatter: add `&` to yielding methods without a block parameter ([#12951](https://github.com/crystal-lang/crystal/pull/12951), thanks @HertzDevil) - Formatter: Add feature flag for `method_signature_yield` ([#13215](https://github.com/crystal-lang/crystal/pull/13215), thanks @straight-shoota) - Macro interpolation: add `&` to yielding `Def`s without a block parameter ([#12952](https://github.com/crystal-lang/crystal/pull/12952), thanks @HertzDevil) ### Infrastructure - Fix `bin/crystal` print no error message when `crystal` is missing ([#12981](https://github.com/crystal-lang/crystal/pull/12981), thanks @straight-shoota) - Prevent infinitely recursive wrapper script ([#11712](https://github.com/crystal-lang/crystal/pull/11712), thanks @ThunderKey) - Changelog helper: Report error from HTTP request ([#13011](https://github.com/crystal-lang/crystal/pull/13011), thanks @straight-shoota) - Fix wrapper script to handle `CRYSTAL` variable pointing to itself ([#13032](https://github.com/crystal-lang/crystal/pull/13032), thanks @straight-shoota) - Propagate exit code correctly in Windows wrapper batch script ([#13048](https://github.com/crystal-lang/crystal/pull/13048), thanks @HertzDevil) - Remove `__declspec(dllimport)` from Windows libiconv build ([#13219](https://github.com/crystal-lang/crystal/pull/13219), thanks @HertzDevil) - Update previous Crystal release - 1.7.0 ([#12925](https://github.com/crystal-lang/crystal/pull/12925), thanks @straight-shoota) - [CI] Remove `verbose=1` in `test_llvm` ([#12931](https://github.com/crystal-lang/crystal/pull/12931), thanks @straight-shoota) - Missing quotes in Wrapper Script ([#12955](https://github.com/crystal-lang/crystal/pull/12955), thanks @stellarpower) - Makefile: refactor test recipe ([#12979](https://github.com/crystal-lang/crystal/pull/12979), thanks @straight-shoota) - Merge release branch for 1.7 into master ([#12998](https://github.com/crystal-lang/crystal/pull/12998), thanks @straight-shoota) - Update previous Crystal release - 1.7.2 ([#13001](https://github.com/crystal-lang/crystal/pull/13001), thanks @straight-shoota) - Update distribution-scripts ([#13051](https://github.com/crystal-lang/crystal/pull/13051), [#13068](https://github.com/crystal-lang/crystal/pull/13068), [#13188](https://github.com/crystal-lang/crystal/pull/13188), [#13213](https://github.com/crystal-lang/crystal/pull/13213), [#13298](https://github.com/crystal-lang/crystal/pull/13298), thanks @straight-shoota) - [CI] Use Ubuntu 22.04 base image for LLVM tests ([#13035](https://github.com/crystal-lang/crystal/pull/13035), thanks @straight-shoota) - Add instructions for other repos to pre-commit hook ([#10535](https://github.com/crystal-lang/crystal/pull/10535), thanks @straight-shoota) - Makefile: Add `./scripts` to `format` recipe ([#13064](https://github.com/crystal-lang/crystal/pull/13064), thanks @straight-shoota) - Crystal wrapper script enhancements ([#12959](https://github.com/crystal-lang/crystal/pull/12959), thanks @j8r) - Fix sed command in `scripts/update-distribution-scripts.cr` ([#13071](https://github.com/crystal-lang/crystal/pull/13071), thanks @straight-shoota) - Update GH Actions ([#13075](https://github.com/crystal-lang/crystal/pull/13075), [#13132](https://github.com/crystal-lang/crystal/pull/13132), thanks @renovate) - CI: Enable testing with `libpcre2` on wasm32 ([#13109](https://github.com/crystal-lang/crystal/pull/13109), thanks @lbguilherme) - Build the compiler with PCRE2 ([#13084](https://github.com/crystal-lang/crystal/pull/13084), [#13133](https://github.com/crystal-lang/crystal/pull/13133), thanks @straight-shoota) - Prefer matching `llvm-config` in `find-llvm-config` ([#13087](https://github.com/crystal-lang/crystal/pull/13087), thanks @straight-shoota) - **(performance)** Run compiler specs in release mode ([#13122](https://github.com/crystal-lang/crystal/pull/13122), thanks @straight-shoota) - [CI] Increase `no_output_timeout` on circleci ([#13151](https://github.com/crystal-lang/crystal/pull/13151), thanks @straight-shoota) - Update NOTICE.md ([#13159](https://github.com/crystal-lang/crystal/pull/13159), thanks @HertzDevil) - Merge `release/1.7`@1.7.3 ([#13168](https://github.com/crystal-lang/crystal/pull/13168), thanks @straight-shoota) - [CI] Cancel in-progress jobs when another commit is pushed ([#13179](https://github.com/crystal-lang/crystal/pull/13179), thanks @Blacksmoke16) - Mute shell comments in Makefile ([#13201](https://github.com/crystal-lang/crystal/pull/13201), thanks @straight-shoota) - Update previous Crystal release - 1.7.3 ([#13167](https://github.com/crystal-lang/crystal/pull/13167), thanks @straight-shoota) - [CI] Remove cross-compilation on Windows ([#13207](https://github.com/crystal-lang/crystal/pull/13207), thanks @straight-shoota) - [CI] Increase `no_output_timeout` on circleci (cont.) ([#13185](https://github.com/crystal-lang/crystal/pull/13185), thanks @straight-shoota) - [CI] Update Windows job to LLVM 15 ([#13208](https://github.com/crystal-lang/crystal/pull/13208), thanks @straight-shoota) - Clean up `.gitignore` ([#13241](https://github.com/crystal-lang/crystal/pull/13241), thanks @straight-shoota) - [CI] Extract LLVM tests in separate workflow ([#13246](https://github.com/crystal-lang/crystal/pull/13246), thanks @straight-shoota) - [CI] Extract interpreter workflow and split `std_spec` execution ([#13267](https://github.com/crystal-lang/crystal/pull/13267), thanks @straight-shoota) - Avoid `test.cr` in root of repo conflicting with parser warning specs ([#13259](https://github.com/crystal-lang/crystal/pull/13259), thanks @Blacksmoke16) - Fix `bin/crystal` in symlink working directory ([#13281](https://github.com/crystal-lang/crystal/pull/13281), thanks @straight-shoota) - Fix `bin/crystal` when no global `crystal` command is installed ([#13286](https://github.com/crystal-lang/crystal/pull/13286), thanks @straight-shoota) - Makefile: Add `interpreter_spec` ([#13251](https://github.com/crystal-lang/crystal/pull/13251), thanks @straight-shoota) - Makefile: Add `all` target as default before including `Makefile.local` ([#13276](https://github.com/crystal-lang/crystal/pull/13276), thanks @straight-shoota) - Update shards 0.17.3 ([#13296](https://github.com/crystal-lang/crystal/pull/13296), thanks @straight-shoota) ### Other - Do not match expectations outside specs ([#13079](https://github.com/crystal-lang/crystal/pull/13079), thanks @HertzDevil) - Enable or fix specs that already work on Windows ([#13186](https://github.com/crystal-lang/crystal/pull/13186), thanks @HertzDevil) ================================================ FILE: doc/changelogs/v1.9.md ================================================ # Changelog 1.9 ## [1.9.2] - 2023-07-19 [1.9.2]: https://github.com/crystal-lang/crystal/releases/1.9.2 ### Bugfixes #### stdlib - _(runtime)_ Revert "Add default interrupt handlers" ([#13673](https://github.com/crystal-lang/crystal/pull/13673), thanks @straight-shoota) ## [1.9.1] - 2023-07-17 [1.9.1]: https://github.com/crystal-lang/crystal/releases/1.9.1 ### Bugfixes #### stdlib - _(serialization)_ Fix `Serializable` with converter parsing `null` value ([#13656](https://github.com/crystal-lang/crystal/pull/13656), thanks @straight-shoota) #### compiler - _(codegen)_ Fix generated cc command for cross compile ([#13661](https://github.com/crystal-lang/crystal/pull/13661), thanks @fnordfish) ## [1.9.0] - 2023-07-11 [1.9.0]: https://github.com/crystal-lang/crystal/releases/1.9.0 ### Breaking changes #### stdlib - _(numeric)_ Handle NaNs when comparing `Big*` numbers against `Float` ([#13293](https://github.com/crystal-lang/crystal/pull/13293), [#13294](https://github.com/crystal-lang/crystal/pull/13294), [#13350](https://github.com/crystal-lang/crystal/pull/13350), [#13554](https://github.com/crystal-lang/crystal/pull/13554), thanks @HertzDevil) - _(llvm)_ Remove most `LLVM::DIBuilder` functions from `llvm_ext.cc` ([#13448](https://github.com/crystal-lang/crystal/pull/13448), thanks @HertzDevil) ### Features #### lang - _(macros)_ Add `warning` macro ([#13262](https://github.com/crystal-lang/crystal/pull/13262), thanks @Blacksmoke16) - _(macros)_ Add `print` macro ([#13336](https://github.com/crystal-lang/crystal/pull/13336), thanks @jkthorne) #### stdlib - _(collection)_ Add `Enumerable#in_slices_of` ([#13108](https://github.com/crystal-lang/crystal/pull/13108), thanks @pricelessrabbit) - _(collection)_ Add support for dash separator to `Enum.parse` ([#13508](https://github.com/crystal-lang/crystal/pull/13508), thanks @straight-shoota) - _(collection)_ Add `Enum#to_i128` and `#to_u128` ([#13576](https://github.com/crystal-lang/crystal/pull/13576), thanks @meatball133) - _(collection)_ Add `Enumerable#partition` overload with type filter ([#13572](https://github.com/crystal-lang/crystal/pull/13572), thanks @baseballlover723) - _(concurrency)_ Support asynchronous `IO.pipe` on Windows ([#13362](https://github.com/crystal-lang/crystal/pull/13362), thanks @HertzDevil) - _(files)_ **[deprecation]** Add `File::MatchOptions` to control `Dir.glob`'s behavior ([#13550](https://github.com/crystal-lang/crystal/pull/13550), thanks @HertzDevil) - _(networking)_ Implement `Socket#reuse_port` on Windows ([#13326](https://github.com/crystal-lang/crystal/pull/13326), thanks @stakach) - _(networking)_ Add multicast support to `UDPSocket` on Windows ([#13325](https://github.com/crystal-lang/crystal/pull/13325), thanks @stakach) - _(networking)_ HTTP Server should allow custom concurrency models ([#13428](https://github.com/crystal-lang/crystal/pull/13428), thanks @stakach) - _(networking)_ Add `Socket::IPaddress.v4`, `.v6`, `.v4_mapped_v6` ([#13422](https://github.com/crystal-lang/crystal/pull/13422), thanks @HertzDevil) - _(networking)_ Add `URI::Params#merge`, `#merge!` and `URI#update_query_params` ([#13415](https://github.com/crystal-lang/crystal/pull/13415), thanks @skinnyjames) - _(networking)_ Support Unix sockets on Windows ([#13493](https://github.com/crystal-lang/crystal/pull/13493), thanks @HertzDevil) - _(networking)_ Add `HTTP::Request#form_params` ([#13418](https://github.com/crystal-lang/crystal/pull/13418), thanks @threez) - _(numeric)_ Add `BigDecimal#%` ([#13255](https://github.com/crystal-lang/crystal/pull/13255), thanks @MattAlp) - _(numeric)_ Improve conversions from `BigInt` to `Int::Primitive` ([#13562](https://github.com/crystal-lang/crystal/pull/13562), thanks @HertzDevil) - _(runtime)_ Print error if unable to delay-load DLL on Windows ([#13475](https://github.com/crystal-lang/crystal/pull/13475), thanks @HertzDevil) - _(runtime)_ Add default interrupt handlers ([#13568](https://github.com/crystal-lang/crystal/pull/13568), thanks @straight-shoota) ⚠️ This was reverted in 1.9.2 - _(serialization)_ Add `ignore_serialize` for `YAML::Serializable` ([#13556](https://github.com/crystal-lang/crystal/pull/13556), thanks @meatball133) - _(specs)_ Add a testcase line number to the output of JUnitFormatter ([#13468](https://github.com/crystal-lang/crystal/pull/13468), thanks @nobodywasishere) - _(specs)_ Publish the `assert_prints` spec helper ([#13599](https://github.com/crystal-lang/crystal/pull/13599), thanks @HertzDevil) - _(system)_ Implement `Process.exec` on Windows ([#13374](https://github.com/crystal-lang/crystal/pull/13374), thanks @HertzDevil) - _(system)_ Add `File::BadExecutableError` ([#13491](https://github.com/crystal-lang/crystal/pull/13491), thanks @HertzDevil) - _(text)_ Add inspection of Regex options support ([#13354](https://github.com/crystal-lang/crystal/pull/13354), thanks @straight-shoota) - _(text)_ Add `Regex.literal` ([#13339](https://github.com/crystal-lang/crystal/pull/13339), thanks @straight-shoota) - _(text)_ Implement `#match!` for Regex ([#13285](https://github.com/crystal-lang/crystal/pull/13285), thanks @devnote-dev) - _(text)_ Add parameters for `Regex::MatchOptions` to matching methods ([#13353](https://github.com/crystal-lang/crystal/pull/13353), thanks @straight-shoota) - _(text)_ Add `Char#titlecase` for correct mixed-case transformations ([#13539](https://github.com/crystal-lang/crystal/pull/13539), thanks @HertzDevil) - _(time)_ Add `start_day` parameter to `Time#at_beginning_of_week` ([#13446](https://github.com/crystal-lang/crystal/pull/13446), thanks @DanielGilchrist) - _(time)_ Map IANA time zone identifiers to Windows time zones ([#13517](https://github.com/crystal-lang/crystal/pull/13517), thanks @HertzDevil) - _(time)_ Add `Time.unix_ns` and `#to_unix_ns` ([#13359](https://github.com/crystal-lang/crystal/pull/13359), thanks @garymardell) #### compiler - Add message about non-release mode to `crystal --version` ([#13254](https://github.com/crystal-lang/crystal/pull/13254), thanks @will) - Respect `%CC%` on Windows ([#13376](https://github.com/crystal-lang/crystal/pull/13376), thanks @HertzDevil) - Support DLL delay-loading on Windows ([#13436](https://github.com/crystal-lang/crystal/pull/13436), thanks @HertzDevil) - Support `-static` and `-dynamic` `.lib` suffixes on Windows ([#13473](https://github.com/crystal-lang/crystal/pull/13473), [#13645](https://github.com/crystal-lang/crystal/pull/13645), thanks @HertzDevil) - Make compiler aware of output extension when building programs ([#13370](https://github.com/crystal-lang/crystal/pull/13370), thanks @HertzDevil) - Support `CRYSTAL_LIBRARY_RPATH` for adding dynamic library lookup paths ([#13499](https://github.com/crystal-lang/crystal/pull/13499), thanks @HertzDevil) - Add compiler command `crystal clear_cache` ([#13553](https://github.com/crystal-lang/crystal/pull/13553), thanks @baseballlover723) - _(codegen)_ Support LLVM 16 ([#13181](https://github.com/crystal-lang/crystal/pull/13181), thanks @HertzDevil) - _(semantic)_ Correctly ignore nested deprecation warnings ([#13513](https://github.com/crystal-lang/crystal/pull/13513), thanks @straight-shoota) #### tools - _(docs-generator)_ Add dark mode to docs ([#13512](https://github.com/crystal-lang/crystal/pull/13512), thanks @GeopJr) - _(docs-generator)_ Add mobile support to docs ([#13515](https://github.com/crystal-lang/crystal/pull/13515), thanks @GeopJr) - _(formatter)_ **[security]** Formatter: escape bi-directional control characters within strings ([#13067](https://github.com/crystal-lang/crystal/pull/13067), thanks @HertzDevil) ### Bugfixes #### stdlib - _(collection)_ Fix `Array#flatten` to discard `Iterator::Stop` ([#13388](https://github.com/crystal-lang/crystal/pull/13388), thanks @straight-shoota) - _(collection)_ Fix return type of `Iterator#chunk` and `Enumerable#chunks` without `Drop` ([#13506](https://github.com/crystal-lang/crystal/pull/13506), thanks @straight-shoota) - _(collection)_ Fix `Iterator#with_index(offset)` with non-`Int32` `offset` ([#13612](https://github.com/crystal-lang/crystal/pull/13612), thanks @HertzDevil) - _(concurrency)_ Fix `preview_mt` infinite loop on Windows ([#13419](https://github.com/crystal-lang/crystal/pull/13419), thanks @HertzDevil) - _(concurrency)_ Fix `Atomic#max` and `#min` for signed enums ([#13524](https://github.com/crystal-lang/crystal/pull/13524), thanks @HertzDevil) - _(concurrency)_ Fix timeout events getting lost on Windows ([#13525](https://github.com/crystal-lang/crystal/pull/13525), thanks @HertzDevil) - _(concurrency)_ Support `Atomic(T)#compare_and_set` when `T` is a reference union ([#13565](https://github.com/crystal-lang/crystal/pull/13565), thanks @HertzDevil) - _(files)_ Fix `Dir#info` on Windows ([#13395](https://github.com/crystal-lang/crystal/pull/13395), thanks @HertzDevil) - _(files)_ Windows: open standard streams in binary mode ([#13397](https://github.com/crystal-lang/crystal/pull/13397), thanks @HertzDevil) - _(files)_ Fix `File.info(File::NULL)` on Windows ([#13421](https://github.com/crystal-lang/crystal/pull/13421), thanks @HertzDevil) - _(files)_ Allow `File.delete` to remove read-only files on Windows ([#13462](https://github.com/crystal-lang/crystal/pull/13462), thanks @HertzDevil) - _(files)_ Make `fcntl` defined on all platforms ([#13495](https://github.com/crystal-lang/crystal/pull/13495), thanks @HertzDevil) - _(files)_ Allow `Dir.delete` to remove read-only directories on Windows ([#13626](https://github.com/crystal-lang/crystal/pull/13626), thanks @HertzDevil) - _(files)_ Use current directory's root for `Dir.glob("/...")` on Windows ([#13628](https://github.com/crystal-lang/crystal/pull/13628), thanks @HertzDevil) - _(llvm)_ Fix `LLVM.default_target_triple` to normalize aarch64 darwin target ([#13597](https://github.com/crystal-lang/crystal/pull/13597), thanks @straight-shoota) - _(log)_ Fix `Log::Builder` append `BroadcastBackend` to itself ([#13405](https://github.com/crystal-lang/crystal/pull/13405), thanks @straight-shoota) - _(macros)_ Fix error message for calling `record` macro with kwargs ([#13367](https://github.com/crystal-lang/crystal/pull/13367), thanks @a-alhusaini) - _(networking)_ Remove double URL escape in `HTTP::Server::Response.redirect` ([#13321](https://github.com/crystal-lang/crystal/pull/13321), thanks @threez) - _(networking)_ Fix WebSocket capitalization in docs ([#13331](https://github.com/crystal-lang/crystal/pull/13331), thanks @joshrickard) - _(networking)_ Fix `TCPSocket#tcp_keepalive_idle` on Windows ([#13364](https://github.com/crystal-lang/crystal/pull/13364), thanks @HertzDevil) - _(networking)_ Fix client-side `TCPSocket#remote_address` on Windows ([#13363](https://github.com/crystal-lang/crystal/pull/13363), thanks @HertzDevil) - _(networking)_ Parse IP addresses in Crystal instead of using `LibC.inet_pton` ([#13463](https://github.com/crystal-lang/crystal/pull/13463), thanks @HertzDevil) - _(networking)_ Windows: do not set `SO_EXCLUSIVEADDRUSE` if `SO_REUSEADDR` already present ([#13477](https://github.com/crystal-lang/crystal/pull/13477), thanks @HertzDevil) - _(networking)_ Implement `Socket::IPAddress#to_s` with Crystal instead of `LibC.inet_ntop` ([#13483](https://github.com/crystal-lang/crystal/pull/13483), thanks @HertzDevil) - _(networking)_ Ensure `Socket` checks `WinError.wsa_value` on Windows, not `Errno.value` ([#13494](https://github.com/crystal-lang/crystal/pull/13494), thanks @HertzDevil) - _(numeric)_ Disallow creating `Big*` numbers from infinity or NaN ([#13351](https://github.com/crystal-lang/crystal/pull/13351), thanks @HertzDevil) - _(numeric)_ Fix `LibM.hypotf` and `ldexpf` link errors on Windows ([#13485](https://github.com/crystal-lang/crystal/pull/13485), thanks @HertzDevil) - _(numeric)_ Make comparisons between `BigRational` and `BigFloat` exact ([#13538](https://github.com/crystal-lang/crystal/pull/13538), thanks @HertzDevil) - _(runtime)_ Fix size of type_id in `Object.set_crystal_type_id` ([#13338](https://github.com/crystal-lang/crystal/pull/13338), thanks @straight-shoota) - _(runtime)_ Allow `/SUBSYSTEM:WINDOWS` on Windows ([#13332](https://github.com/crystal-lang/crystal/pull/13332), thanks @HertzDevil) - _(runtime)_ Use correct format strings for crash stack traces ([#13408](https://github.com/crystal-lang/crystal/pull/13408), thanks @HertzDevil) - _(serialization)_ Fix handling of quoted boolean values in `YAML::Any` ([#13546](https://github.com/crystal-lang/crystal/pull/13546), thanks @willhbr) - _(serialization)_ Fix ambiguous call with untyped int literal in `{JSON,YAML}::Any.new` ([#13618](https://github.com/crystal-lang/crystal/pull/13618), thanks @straight-shoota) - _(system)_ Fix for Process: ensure chdir is a string ([#13503](https://github.com/crystal-lang/crystal/pull/13503), thanks @devnote-dev) - _(system)_ Windows: drop internal environment variables from `ENV` ([#13570](https://github.com/crystal-lang/crystal/pull/13570), thanks @HertzDevil) - _(text)_ Fix `String#underscore` with multi-character downcasing ([#13540](https://github.com/crystal-lang/crystal/pull/13540), thanks @HertzDevil) - _(text)_ Do not attempt downcasing first when case-folding a `Char` ([#13542](https://github.com/crystal-lang/crystal/pull/13542), thanks @HertzDevil) - _(text)_ Handle case folding in `String#compare` correctly ([#13532](https://github.com/crystal-lang/crystal/pull/13532), thanks @HertzDevil) - _(time)_ Update list of Windows time zones ([#13501](https://github.com/crystal-lang/crystal/pull/13501), thanks @HertzDevil) - _(time)_ Fix local timezones without DST on Windows ([#13516](https://github.com/crystal-lang/crystal/pull/13516), thanks @HertzDevil) - _(time)_ Fix leap second handling for timezone information files ([#13600](https://github.com/crystal-lang/crystal/pull/13600), thanks @HertzDevil) #### compiler - More accurate macro errors ([#13260](https://github.com/crystal-lang/crystal/pull/13260), thanks @Blacksmoke16) - Do not drop `/LIBPATH` from Windows linker command ([#13530](https://github.com/crystal-lang/crystal/pull/13530), thanks @HertzDevil) - Fix instantiated method signatures in error traces ([#13580](https://github.com/crystal-lang/crystal/pull/13580), thanks @HertzDevil) - Place `--emit` files back in current directory when running source ([#13604](https://github.com/crystal-lang/crystal/pull/13604), thanks @HertzDevil) - _(generics)_ Fix free variable matching of bound numeric values ([#13606](https://github.com/crystal-lang/crystal/pull/13606), thanks @HertzDevil) - _(parser)_ Don't skip the token immediately after `lib` name ([#13407](https://github.com/crystal-lang/crystal/pull/13407), thanks @FnControlOption) - _(parser)_ Allow newline after hash rocket ([#13460](https://github.com/crystal-lang/crystal/pull/13460), thanks @FnControlOption) - _(parser)_ Add missing locations of various AST nodes ([#13452](https://github.com/crystal-lang/crystal/pull/13452), thanks @FnControlOption) - _(parser)_ Fix AST location of call name in operator assignment ([#13456](https://github.com/crystal-lang/crystal/pull/13456), thanks @FnControlOption) #### tools - Display `Bool`'s size as 1 byte in `crystal tool hierarchy`, not 0 ([#13588](https://github.com/crystal-lang/crystal/pull/13588), thanks @HertzDevil) ### Performance #### stdlib - _(collection)_ Optimize `Array#concat(Indexable)` ([#13280](https://github.com/crystal-lang/crystal/pull/13280), thanks @HertzDevil) - _(collection)_ Optimize `Deque#concat(Indexable)` ([#13283](https://github.com/crystal-lang/crystal/pull/13283), thanks @HertzDevil) - _(concurrency)_ Support synchronous socket operations on Windows ([#13414](https://github.com/crystal-lang/crystal/pull/13414), thanks @HertzDevil) - _(numeric)_ Optimize `BigInt.new(Int::Primitive)` ([#13303](https://github.com/crystal-lang/crystal/pull/13303), thanks @HertzDevil) - _(numeric)_ Optimize `BigRational#<=>(Int)` ([#13555](https://github.com/crystal-lang/crystal/pull/13555), thanks @HertzDevil) - _(text)_ Improve `HTML.escape(string, io)` performance ([#13139](https://github.com/crystal-lang/crystal/pull/13139), thanks @BlobCodes) - _(text)_ Refactor `String.ends_with?` to use `MatchOptions::ENDANCHORED` ([#13551](https://github.com/crystal-lang/crystal/pull/13551), thanks @straight-shoota) #### tools - _(docs-generator)_ Optimize `Doc::Method#compute_doc_info` to avoid duplicate regex ([#13324](https://github.com/crystal-lang/crystal/pull/13324), thanks @straight-shoota) ### Refactor #### stdlib - Use sentence case for all standard library exceptions ([#13400](https://github.com/crystal-lang/crystal/pull/13400), thanks @HertzDevil) - _(collection)_ Refactor code for `Deque` buffer resizing ([#13257](https://github.com/crystal-lang/crystal/pull/13257), thanks @HertzDevil) - _(concurrency)_ Clean up unused code for Windows event loop ([#13424](https://github.com/crystal-lang/crystal/pull/13424), thanks @HertzDevil) - _(files)_ Do not reopen current file in `File#utime` on Windows ([#13625](https://github.com/crystal-lang/crystal/pull/13625), thanks @HertzDevil) - _(files)_ Do not reopen current file in `File#chmod` on Windows ([#13627](https://github.com/crystal-lang/crystal/pull/13627), thanks @HertzDevil) - _(llvm)_ **[deprecation]** Deprecate `LLVM::Module#write_bitcode_with_summary_to_file` ([#13488](https://github.com/crystal-lang/crystal/pull/13488), thanks @HertzDevil) - _(llvm)_ **[deprecation]** Deprecate LLVM's legacy pass manager ([#13579](https://github.com/crystal-lang/crystal/pull/13579), thanks @HertzDevil) - _(llvm)_ Remove two outdated LLVM fun bindings ([#13438](https://github.com/crystal-lang/crystal/pull/13438), thanks @HertzDevil) - _(llvm)_ Split `LLVM::Builder` overloads that don't take an operand bundle ([#13564](https://github.com/crystal-lang/crystal/pull/13564), thanks @HertzDevil) - _(networking)_ Move more `Socket` methods to `Crystal::System::Socket` ([#13346](https://github.com/crystal-lang/crystal/pull/13346), thanks @HertzDevil) - _(numeric)_ Use `Int#bit_length` instead of `Math.log2` followed by `#to_i` ([#13440](https://github.com/crystal-lang/crystal/pull/13440), thanks @HertzDevil) - _(numeric)_ Use GMP's functions for `Float`-to-`BigRational` conversion ([#13352](https://github.com/crystal-lang/crystal/pull/13352), thanks @HertzDevil) - _(serialization)_ Simplify implementation of `Serializable#initialize` ([#13433](https://github.com/crystal-lang/crystal/pull/13433), thanks @straight-shoota) - _(serialization)_ Use per-thread libxml2 global state on Windows ([#13486](https://github.com/crystal-lang/crystal/pull/13486), thanks @HertzDevil) - _(text)_ Refactor String header layout reflection ([#13335](https://github.com/crystal-lang/crystal/pull/13335), thanks @straight-shoota) - _(text)_ Refactor symbol quoting into `Symbol.quote_for_named_argument` ([#13595](https://github.com/crystal-lang/crystal/pull/13595), thanks @straight-shoota) #### compiler - _(parser)_ Crystal lexer cleanup ([#13270](https://github.com/crystal-lang/crystal/pull/13270), thanks @FnControlOption) - _(parser)_ Don't use symbols in `Crystal::Lexer#check_macro_opening_keyword` ([#13277](https://github.com/crystal-lang/crystal/pull/13277), thanks @HertzDevil) ### Documentation #### stdlib - _(concurrency)_ Fix operators in `Atomic#add`, `#sub`, `#max`, `#min` ([#13523](https://github.com/crystal-lang/crystal/pull/13523), thanks @HertzDevil) - _(concurrency)_ Hide `Crystal::LibEvent` from public docs ([#13624](https://github.com/crystal-lang/crystal/pull/13624), thanks @HertzDevil) - _(macros)_ Fix doc for return type of `Crystal::Macros::Case#else` ([#13385](https://github.com/crystal-lang/crystal/pull/13385), thanks @HertzDevil) - _(system)_ Reference `Process.executable_path` at `PROGRAM_NAME` ([#13434](https://github.com/crystal-lang/crystal/pull/13434), thanks @straight-shoota) - _(text)_ Add note about graphemes in `String#reverse` ([#13536](https://github.com/crystal-lang/crystal/pull/13536), thanks @noraj) #### compiler - Add manual entry for `clear_cache` command ([#13621](https://github.com/crystal-lang/crystal/pull/13621), thanks @straight-shoota) #### other - Implemented ',' command in brainfuck sample program ([#13559](https://github.com/crystal-lang/crystal/pull/13559), thanks @ZeroPlayerRodent) ### Specs #### stdlib - _(files)_ Fix `IO::FileDescriptor`'s `STDIN` mode spec ([#13365](https://github.com/crystal-lang/crystal/pull/13365), thanks @HertzDevil) - _(files)_ Fix file permission specs on Windows ([#13465](https://github.com/crystal-lang/crystal/pull/13465), thanks @HertzDevil) - _(files)_ Add `slow` tag to stdlib specs that compile a program ([#13498](https://github.com/crystal-lang/crystal/pull/13498), thanks @straight-shoota) - _(serialization)_ Refactor JSON, YAML specs for #13337 for simplicity ([#13358](https://github.com/crystal-lang/crystal/pull/13358), thanks @straight-shoota) - _(system)_ Disable `Process.pgid` spec on Windows ([#13476](https://github.com/crystal-lang/crystal/pull/13476), thanks @HertzDevil) - _(text)_ Reorder and enhance specs for `String.new(&)` ([#13333](https://github.com/crystal-lang/crystal/pull/13333), thanks @straight-shoota) - _(text)_ Remove incorrect `CRYSTAL` in comments ([#13500](https://github.com/crystal-lang/crystal/pull/13500), thanks @HertzDevil) - _(time)_ Skip `Time::Location.load_local` spec if unable to change time zone ([#13355](https://github.com/crystal-lang/crystal/pull/13355), thanks @HertzDevil) #### compiler - _(interpreter)_ Regenerate `spec/interpreter_std_spec.cr` ([#13310](https://github.com/crystal-lang/crystal/pull/13310), thanks @cyangle) ### Infrastructure - Update changelog with previous Crystal releases ([#13322](https://github.com/crystal-lang/crystal/pull/13322), [#13373](https://github.com/crystal-lang/crystal/pull/13373), [#13450](https://github.com/crystal-lang/crystal/pull/13450), thanks @straight-shoota) - Merge `release/1.8` ([#13361](https://github.com/crystal-lang/crystal/pull/13361), [#13449](https://github.com/crystal-lang/crystal/pull/13449), thanks @straight-shoota) - PR template: adding a line about force-pushes ([#12794](https://github.com/crystal-lang/crystal/pull/12794), thanks @beta-ziliani) - Less verbose output in `Makefile.win` ([#13383](https://github.com/crystal-lang/crystal/pull/13383), thanks @HertzDevil) - Update distribution-scripts ([#13457](https://github.com/crystal-lang/crystal/pull/13457), thanks @Blacksmoke16) - Add `.gitattributes` to repository ([#13479](https://github.com/crystal-lang/crystal/pull/13479), thanks @HertzDevil) - Update `shell.nix` to nixpkgs-23.05 ([#13571](https://github.com/crystal-lang/crystal/pull/13571), thanks @HertzDevil) - Document `target` variable in Makefiles ([#13384](https://github.com/crystal-lang/crystal/pull/13384), thanks @HertzDevil) - Fix `bin\crystal.ps1` writing to standard error stream ([#13372](https://github.com/crystal-lang/crystal/pull/13372), thanks @HertzDevil) - Avoid calling realpath of parent crystal in wrapper script ([#13596](https://github.com/crystal-lang/crystal/pull/13596), thanks @straight-shoota) - _(ci)_ Show PCRE/PCRE2 configuration on CI ([#13307](https://github.com/crystal-lang/crystal/pull/13307), thanks @HertzDevil) - _(ci)_ Update cachix/install-nix-action action ([#13531](https://github.com/crystal-lang/crystal/pull/13531), [#13586](https://github.com/crystal-lang/crystal/pull/13586), thanks @renovate) - _(ci)_ Restrict Windows CI jobs for installer packages to release branches ([#13623](https://github.com/crystal-lang/crystal/pull/13623), thanks @HertzDevil) - _(ci)_ Build samples on Windows CI ([#13334](https://github.com/crystal-lang/crystal/pull/13334), thanks @HertzDevil) - _(ci)_ Do not cancel in progress CI jobs for master branch ([#13393](https://github.com/crystal-lang/crystal/pull/13393), thanks @Blacksmoke16) - _(ci)_ Upgrade Windows CI to LLVM 16 ([#13469](https://github.com/crystal-lang/crystal/pull/13469), thanks @HertzDevil) - _(ci)_ Distribute DLLs and import libraries on Windows ([#13543](https://github.com/crystal-lang/crystal/pull/13543), thanks @HertzDevil) - _(ci)_ Build Windows portable and installer packages on CI ([#13578](https://github.com/crystal-lang/crystal/pull/13578), thanks @HertzDevil) - _(ci)_ Split Windows library build scripts from CI ([#13478](https://github.com/crystal-lang/crystal/pull/13478), thanks @HertzDevil) ================================================ FILE: doc/man/crystal-build.adoc ================================================ = crystal-build(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-build - Compile a Crystal program == Synopsis *crystal build* [options] [programfile] [--] [arguments] == Options *--cross-compile*:: Generate an object file for cross compilation and prints the command to build the executable. The object file should be copied to the target system and the printed command should be executed there. This flag mainly exists for porting the compiler to new platforms, where possible run the compiler on the target platform directly. *-d*, *--debug*:: Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. *--no-debug*:: Generate the output without any symbolic debug symbols. *-D* _FLAG_, *--define* _FLAG_:: Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with *--target-triple* or the hosts default, if none is given. *--emit* [asm|llvm-bc|llvm-ir|obj]:: Comma separated list of types of output for the compiler to emit. You can use this to see the generated LLVM IR, LLVM bitcode, assembly, and object files. *--x86-asm-syntax* [att|intel]:: Select the assembly dialect for *--emit=asm*. The default is `att`, which stands for the AT&T syntax supported by tools like the GNU Assembler. `intel` selects the Intel syntax which is preferred for Windows tools. *--frame-pointers* [auto|always|non-leaf]:: Control the preservation of frame pointers. The default value, `--frame-pointers=auto`, will preserve frame pointers on debug builds and try to omit them on release builds (certain platforms require them to stay enabled). `--frame-pointers=always` will always preserve them, and non-leaf will only force their preservation on non-leaf functions. *-f* text|json, *--format* text|json:: Format of output. Defaults to text. The json format can be used to get a more parser-friendly output. *--error-trace*:: Show full error trace. Disabled by default, as the full trace usually makes error messages less readable and may not always deliver relevant information. *--ll*:: Dump LLVM assembly file to output directory. *--link-flags* _FLAGS_:: Pass additional flags to the linker. Though you can specify those flags on the source code, this is useful for passing environment specific information directly to the linker, like non-standard library paths or names. For more information on specifying linker flags on source, you can read the "C bindings" section of the documentation available on the official web site. *--mcpu* _CPU_:: Specify a specific CPU to generate code for. This will pass a -mcpu flag to LLVM, and is only intended to be used for cross- compilation. For a list of available CPUs, pass --mcpu help when building any Crystal source code. Passing --mcpu native will pass the host CPU name to tune performance for the host. *--mattr* _CPU_:: Override or control specific attributes of the target, such as whether SIMD operations are enabled or not. The default set of attributes is set by the current CPU. This will pass a -mattr flag to LLVM, and is only intended to be used for cross-compilation. For a list of available attributes, invoke "llvm-as < /dev/null | llc -march=xyz -mattr=help". *--mcmodel* default|kernel|tiny|small|medium|large:: Specifies a specific code model to generate code for. This will pass a --code-model flag to LLVM. *--no-color*:: Disable colored output. *--no-codegen*:: Don't do code generation, just parse the file. *-o* _FILE_, *--output* _FILE_:: Specify output path. If a directory, the filename is derived from the first source file (default: current directory) *--prelude*:: Specify prelude to use. The default one initializes the garbage collector. You can also use --prelude=empty to use no preludes. This can be useful for checking code generation for a specific source code file. *-O* _LEVEL_:: Optimization mode: 0 (default), 1, 2, 3. See *OPTIMIZATIONS* for details. *--release*:: Compile in release mode. Equivalent to *-O3 --single-module* *-s*, *--stats*:: Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. *-p*, *--progress*:: Print statistics about the progress for the current build. *-t*, *--time*:: Print statistics about the execution time. *--single-module*:: Generate a single LLVM module. By default, one LLVM module is created for each type in a program. *--release* implies this option. *--threads* _NUM_:: Maximum number of threads to use for code generation. The default is 8 threads. *--target* _TRIPLE_:: Enable target triple; intended to use for cross-compilation. See llvm documentation for more information about target triple. *--verbose*:: Display the commands executed by the system. *--static*:: Create a statically linked executable. *--stdin-filename* _FILENAME_:: Source file name to be read from STDIN. ================================================ FILE: doc/man/crystal-docs.adoc ================================================ = crystal-docs(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-doc - Generate API docs for Crystal code == Synopsis *crystal build* [options] [programfile] [--] [arguments] == Description Generate documentation from comments using a subset of markdown. The output is saved in html format on the created docs/ folder. More information about documentation conventions can be found at . == Options *--project-name* _NAME_:: Set the project name. The default value is extracted from shard.yml if available. + In case no default can be found, this option is mandatory. *--project-version* _VERSION_:: Set the project version. The default value is extracted from current git commit or shard.yml if available. + In case no default can be found, this option is mandatory. *--json-config-url* _URL_:: Set the URL pointing to a config file (used for discovering versions). *--source-refname* _REFNAME_:: Set source refname (e.g. git tag, commit hash). The default value is extracted from current git commit if available. + If this option is missing and can't be automatically determined, the generator can't produce source code links. *--source-url-pattern* _URL_:: Set URL pattern for source code links. The default value is extracted from git remotes ("origin" or first one) if available and the provider's URL pattern is recognized. + Supported replacement tags: + -- *%{refname}*:: commit reference *%{path}*:: path to source file inside the repository *%{filename}*:: basename of the source file *%{line}*:: line number -- + If this option is missing and can't be automatically determined, the generator can't produce source code links. *-o* _DIR_, *--output* _DIR_:: Set the output directory (default: ./docs). *-b* _URL_, **--canonical-base-url** _URL_:: Indicate the preferred URL with rel="canonical" link element. *-b* _URL_, *--sitemap-base-url* _URL_:: Set the sitemap base URL. Sitemap will only be generated when this option is set. *--sitemap-priority* _PRIO_:: Set the priority assigned to sitemap entries (default: 1.0). *--sitemap-changefreq* _FREQ_:: Set the changefreq assigned to sitemap entries (default: never). ================================================ FILE: doc/man/crystal-env.adoc ================================================ = crystal-env(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-env - Print environment variables for the Crystal compiler == Synopsis *crystal env* [variables] == Description Print Crystal-specific environment variables in a format compatible with shell scripts. If one or more variable names are given as arguments, it prints only the value of each named variable on its own line. Variables: *CRYSTAL_CACHE_DIR*:: Please see ENVIRONMENT VARIABLES. *CRYSTAL_EXEC_PATH*:: Please see ENVIRONMENT VARIABLES. *CRYSTAL_LIBRARY_PATH*:: Please see ENVIRONMENT VARIABLES. *CRYSTAL_PATH*:: Please see ENVIRONMENT VARIABLES. *CRYSTAL_VERSION*:: Contains Crystal version. == Informative Variables These variables expose information about the Crystal compiler and cannot be configured externally. === CRYSTAL_VERSION Contains Crystal version. ================================================ FILE: doc/man/crystal-eval.adoc ================================================ = crystal-eval(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-eval - Evaluate a crystal program == Synopsis *crystal eval* [options] [source] == Description Evaluate code from arguments or, if no arguments are passed, from the standard input. Useful for experiments. == Options *-d*, *--debug*:: Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. *--no-debug*:: Generate the output without any symbolic debug symbols. *-D* _FLAG_, *--define* _FLAG_:: Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given. *--error-trace*:: Show full error trace. *-O* _LEVEL_:: Optimization mode: 0 (default), 1, 2, 3. See *OPTIMIZATIONS* for details. *--release*:: Compile in release mode. Equivalent to *-O3 --single-module* *-s*, *--stats*:: Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. *-p*, *--progress*:: Print statistics about the progress for the current build. *-t*, *--time*:: Print statistics about the execution time. *--no-color*:: Disable colored output. ================================================ FILE: doc/man/crystal-init.adoc ================================================ = crystal-init(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-init - Create a a new Crystal project == Synopsis *crystal init* TYPE [DIR | NAME DIR] == Description TYPE is one of: *lib* Creates a library skeleton + *app* Creates an application skeleton This initializes the lib/app project folder as a git repository, with a license file, a README file, a shard.yml for use with shards (the Crystal dependency manager), a .gitignore file, and src and spec folders. DIR - directory where project will be generated NAME - name of project to be generated (default: basename of DIR) == Options *-f, --force*:: Force overwrite existing files. *-s, --skip-existing*:: Skip existing files. ================================================ FILE: doc/man/crystal-play.adoc ================================================ = crystal-play(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-play - Run the Crystal playground == Synopsis *crystal play* [options] [file] == Description Starts the *crystal* playground server on port 8080, by default. == Options *-p* _PORT_, *--port* _PORT_:: Run the playground on the specified port. Default is 8080. *-b* _HOST_, *--binding* _HOST_:: Bind the playground to the specified IP. *-v*, *--verbose*:: Display detailed information of the executed code. ================================================ FILE: doc/man/crystal-run.adoc ================================================ = crystal-run(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-run - Compile and run a Crystal program == Synopsis *crystal run* [options] [programfile] [--] [arguments] == Description The default command. Compile and run program. == Options Same as the build options. ================================================ FILE: doc/man/crystal-spec.adoc ================================================ = crystal-spec(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-spec - Compile and run Crystal spec files == Synopsis *crystal spec* [options] [files] == Options *-d*, *--debug*:: Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. *--no-debug*:: Generate the output without any symbolic debug symbols. *-D* _FLAG_, *--define* _FLAG_:: Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with *--target-triple* or the hosts default, if none is given. *--error-trace*:: Show full error trace. *-O* _LEVEL_:: Optimization mode: 0 (default), 1, 2, 3. See *OPTIMIZATIONS* for details. *--release*:: Compile in release mode. Equivalent to *-O3 --single-module* *-s*, *--stats*:: Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. *-p*, *--progress*:: Print statistics about the progress for the current build. *-t*, *--time*:: Print statistics about the execution time. *--no-color*:: Disable colored output. ================================================ FILE: doc/man/crystal-tool-dependencies.adoc ================================================ = crystal-tool-dependencies(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-tool-dependencies - Show tree of required source files. == Synopsis *crystal tool dependencies* [options] [programfile] == Options *-D* _FLAG_, *--define*=_FLAG_:: Define a compile-time flag. This is useful to con ditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with *--tar* get-triple or the hosts default, if none is given. *-f* _FORMAT_, *--format*=_FORMAT_:: Output format 'tree' (default), 'flat', 'dot', or 'mermaid'. *-i* _PATH_, *--include*=_PATH_:: Include path in output. *-e* _PATH_, *--exclude*=_PATH_:: Exclude path in output. *--error-trace*:: Show full error trace. *--prelude*:: Specify prelude to use. The default one initializes the garbage collector. You can also use *--pre* lude=empty to use no preludes. This can be useful for checking code generation for a specific source code file. *--verbose*:: Show skipped and heads of filtered paths ================================================ FILE: doc/man/crystal-tool-format.adoc ================================================ = crystal-tool-format(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-tool-format - Format Crystal source files == Synopsis *crystal tool format* [options] [source...] == Description Format project, directories and/or files with the coding style used in the standard library. == Options *--check*:: Only check conformity but do not apply any changes. ================================================ FILE: doc/man/crystal-tool-macro_code_coverage.adoc ================================================ = crystal-tool-macro_code_coverage(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-tool-macro_code_coverage - generate a macro code coverage report. == Synopsis *crystal tool macro_code_coverage* [options] [programfile] == Description Generate and output a macro code coverage report to STDERR. Any exception raised while computing the report is written to STDOUT. == Options *-D* _FLAG_, *--define*=_FLAG_:: Define a compile-time flag. This is useful to con ditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with *--tar* get-triple or the hosts default, if none is given. *-f* _FORMAT_, *--format*=_FORMAT_:: Output format 'codecov' (default). *-i* _PATH_, *--include*=_PATH_:: Include path in output. *-e* _PATH_, *--exclude*=_PATH_:: Exclude path in output (default: lib). *--error-trace*:: Show full error trace. *--prelude*:: Specify prelude to use. The default one initializes the garbage collector. You can also use *--pre* lude=empty to use no preludes. This can be useful for checking code generation for a specific source code file. *-s*, *--stats*:: Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. *-p*, *--progress*:: Print statistics about the progress for the current build. *-t*, *--time*:: Print statistics about the execution time. *--no-color*:: Disable colored output. ================================================ FILE: doc/man/crystal-tool-unreachable.adoc ================================================ = crystal-tool-unreachable(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal-tool-unreachable - Identify methods that are never called == Synopsis *crystal tool unreachable* [options] [source...] == Description Show methods that are never called. The text output is a list of lines with columns separated by tab. Output fields: *count*:: sum of all calls to this method (only with *--tallies* option; otherwise skipped) *location*:: pathname, line and column, all separated by colon name *lines*:: length of the def in lines annotations == Options *-D* _FLAG_, *--define*=_FLAG_:: Define a compile-time flag. This is useful to con ditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with *--target-triple* or the hosts default, if none is given. *-f* _FORMAT_, *--format*=_FORMAT_:: Output format 'text' (default), 'json', 'codecov', or 'csv'. *--tallies*:: Print reachable methods and their call counts as well. *--check*:: Exit with error if there is any unreachable code. *-i* _PATH_, *--include*=_PATH_:: Include path in output. *-e* _PATH_, *--exclude*=_PATH_:: Exclude path in output (default: lib). *--error-trace*:: Show full error trace. *--prelude*:: Specify prelude to use. The default one initializes the garbage collector. You can also use *--prelude=empty* to use no preludes. This can be useful for checking code generation for a specific source code file. ================================================ FILE: doc/man/crystal.adoc ================================================ = crystal(1) :doctype: manpage :date: {localdate} :crystal_version: {crystal_version} :man manual: Crystal Compiler Command Line Reference Guide :man source: crystal {crystal_version} == Name crystal - compiler for the Crystal language == Synopsis *crystal* command [switches] programfile -- [arguments] == Description Crystal is a statically type-checked programming language. It was created with the beauty of Ruby and the performance of C in mind. == Usage You can compile and run a program by invoking the compiler with a single filename: ```shell crystal some_program.cr ``` Crystal files usually end with the .cr extension, though this is not mandatory. Alternatively you can use the run command: ```shell crystal run some_program.cr ``` To create an executable use the build command: ```shell crystal build some_program.cr ``` This will create an executable named "some_program". Note that by default the generated executables are not fully optimized. To turn optimizations on, use the *--release* flag: ```shell crystal build --release some_program.cr ``` Make sure to always use *--release* for production-ready executables and when performing benchmarks. The optimizations are not turned on by default because the compile times are much faster without them and the performance of the program is still pretty good without them, so it allows to use the *crystal* command almost to be used as if it was an interpreter. == Crystal Commands === Main commands *crystal-init(1)*:: Create a a new Crystal project *crystal-build(1)*:: Compile a Crystal program *crystal-docs(1)*:: Generate API docs for Crystal code *crystal-env(1)*:: Print environment variables for the Crystal compiler *crystal-eval(1)*:: Evaluate a crystal program *crystal-play(1)*:: Run the Crystal playground *crystal-run(1)*:: Compile and run a Crystal program *crystal-spec(1)*:: Compile and run Crystal spec files *crystal-clear_cache*:: Clear the compiler cache (located at 'CRYSTAL_CACHE_DIR'). *crystal-help*:: Show help. Option *--help* or *-h* can also be added to each command for command-specific help. *crystal-version*:: Show version. === Tools *crystal-tool-context*:: Show context for given location *crystal-tool-dependencies(1)*:: Show tree of required source files *crystal-tool-expand*:: Show macro expansion for given location *crystal-tool-flags*:: Print all macro 'flag?' values *crystal-tool-format(1)*:: Format Crystal source files *crystal-tool-hierarchy*:: Show hierarchy of types from file. Also show class and struct members, with type and size. Types can be filtered with a regex by using the *-e* flag. *crystal-tool-implementations*:: Show implementations for a given call. Use *--cursor* to specify the cursor position. The format for the cursor position is file:line:column. *crystal-tool-macro_code_coverage*:: Generate a macro code coverage report. *crystal-tool-types*:: Show type of main variables of file. *crystal-tool-unreachable(1)*:: Identify methods that are never called == Optimizations The optimization level specifies the codegen effort for producing optimal code. It's a trade-off between compilation performance (decreasing per optimization level) and runtime performance (increasing per optimization level). Production builds should usually have the highest optimization level. Best results are achieved with *--release* which also implies *--single-module* *-O0*:: No optimization (default) *-O1*:: Low optimization *-O2*:: Middle optimization *-O3*:: High optimization *-Os*:: Middle optimization with focus on file size *-Oz*:: Middle optimization aggressively focused on file size == Environment Variables === CRYSTAL_CACHE_DIR Defines path where Crystal caches partial compilation results for faster subsequent builds. This path is also used to temporarily store executables when Crystal programs are run with '*crystal* run' rather than '*crystal* build'. === CRYSTAL_EXEC_PATH Determines the path where *crystal* looks for external sub-commands. === CRYSTAL_LIBRARY_PATH Defines paths where Crystal searches for (binary) libraries. Multiple paths can be separated by ":". These paths are passed to the linker as `-L` flags. The pattern '$ORIGIN' at the start of the path expands to the directory where the compiler binary is located. For example, '$ORIGIN/../lib/crystal' resolves the standard library path relative to the compiler location in a generic way, independent of the absolute paths (assuming the relative location is correct). === CRYSTAL_PATH Defines paths where Crystal searches for required source files. Multiple paths can be separated by ":". The pattern '$ORIGIN' at the start of the path expands to the directory where the compiler binary is located. For example, '$ORIGIN/../share/crystal/src' resolves the standard library path relative to the compiler location in a generic way, independent of the absolute paths (assuming the relative location is correct). === CRYSTAL_OPTS Defines options for the Crystal compiler to be used besides the command line arguments. The syntax is identical to the command line arguments. This is handy when using Crystal in build setups, for example 'CRYSTAL_OPTS=--debug make build'. == Seealso *shards*(1) The official web site. Official Repository. ================================================ FILE: etc/completion.bash ================================================ # Bash completion for "crystal" command. # Written by Sergey Potapov . # Return list of options, that match $pattern _crystal_compgen_options(){ local options=$1 local pattern=$2 while IFS=$' \n' read -r line; do COMPREPLY+=("$line") done < <(compgen -W "${options}" -- "${pattern}") } # Return list of crystal sources or directories, that match $pattern _crystal_compgen_sources(){ local pattern=$1 type compopt &> /dev/null && compopt -o filenames while IFS=$'\n' read -r line; do COMPREPLY+=("$line") done < <(compgen -f -o plusdirs -X '!*.cr' -- "${pattern}") } # Return list of files or directories, that match $pattern (the default action) _crystal_compgen_files(){ local pattern=$1 type compopt &> /dev/null && compopt -o filenames while IFS=$'\n' read -r line; do COMPREPLY+=("$line") done < <(compgen -o default -- "${pattern}") } _crystal() { local IFS=$' \n' local program=${COMP_WORDS[0]} local cmd=${COMP_WORDS[1]} local cur="${COMP_WORDS[COMP_CWORD]}" local prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() commands="init build clear_cache docs eval play run spec tool help version --help --version" case "${cmd}" in init) if [[ "${prev}" == "init" ]] ; then local opts="app lib" _crystal_compgen_options "${opts}" "${cur}" else _crystal_compgen_files "${cur}" fi ;; build) if [[ "${cur}" == -* ]] ; then local opts="--cross-compile --debug --emit --error-on-warnings --exclude-warnings --ll --link-flags --mcpu --no-color --no-codegen --output --prelude --release --single-module --threads --target --verbose --warnings --x86-asm-syntax --help" _crystal_compgen_options "${opts}" "${cur}" else _crystal_compgen_sources "${cur}" fi ;; run) if [[ "${cur}" == -* ]] ; then local opts="--debug --define --emit --error-on-warnings --exclude-warnings --format --help --ll --link-flags --mcpu --no-color --no-codegen --output --prelude --release --stats --single-module --threads --verbose --warnings --x86-asm-syntax" _crystal_compgen_options "${opts}" "${cur}" else _crystal_compgen_sources "${cur}" fi ;; tool) if [[ "${cur}" == -* ]] ; then local opts="--no-color --prelude --define --format --cursor" _crystal_compgen_options "${opts}" "${cur}" else if [[ "${prev}" == "tool" ]] ; then local subcommands="context dependencies expand flags format hierarchy implementations macro_code_coverage types unreachable" _crystal_compgen_options "${subcommands}" "${cur}" else _crystal_compgen_sources "${cur}" fi fi ;; play) if [[ ${cur} == -* ]] ; then local opts="--port --binding --verbose --help" _crystal_compgen_options "${opts}" "${cur}" else _crystal_compgen_sources "${cur}" fi ;; clear_cache|docs|eval|spec|version|help) # These commands do not accept any options nor subcommands _crystal_compgen_files "${cur}" ;; *) # When any of subcommands matches directly if [[ "${prev}" == "${program}" && $(compgen -W "${commands}" -- "${cur}") ]] ; then _crystal_compgen_options "${commands}" "${cur}" else _crystal_compgen_sources "${cur}" fi esac return 0 } complete -F _crystal crystal ================================================ FILE: etc/completion.fish ================================================ set -l crystal_commands init build clear_cache docs env eval i interactive play run spec tool help version set -l tool_subcommands context dependencies expand flags format hierarchy implementations types unreachable complete -c crystal -s h -l help -d "Show help" -x complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "init" -d "Generate a new project" complete -c crystal -f -n "__fish_seen_subcommand_from init" -a "lib" -d "Creates a library skeleton" complete -c crystal -f -n "__fish_seen_subcommand_from init" -a "app" -d "Creates an application skeleton" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "build" -d "Build an executable" complete -c crystal -n "__fish_seen_subcommand_from build" -l cross-compile -d "cross-compile" complete -c crystal -n "__fish_seen_subcommand_from build" -s d -l debug -d "Add full symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from build" -l no-debug -d "Skip any symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from build" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from build" -l emit -d "Comma separated list of types of output for the compiler to emit" -a "asm obj llvm-bc llvm-ir" -f complete -c crystal -n "__fish_seen_subcommand_from build" -l x86-asm-syntax -d "X86 dialect for --emit=asm: att (default), intel" -a "att intel" -f complete -c crystal -n "__fish_seen_subcommand_from build" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from build" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from build" -l ll -d "Dump ll to Crystal's cache directory" complete -c crystal -n "__fish_seen_subcommand_from build" -l link-flags -d "Additional flags to pass to the linker" complete -c crystal -n "__fish_seen_subcommand_from build" -l mcpu -d "Target specific cpu type" complete -c crystal -n "__fish_seen_subcommand_from build" -l mattr -d "Target specific features" complete -c crystal -n "__fish_seen_subcommand_from build" -l mcmodel -d "Target specific code model" complete -c crystal -n "__fish_seen_subcommand_from build" -l warnings -d "Which warnings detect. (default: all)" -a "all none" -f complete -c crystal -n "__fish_seen_subcommand_from build" -l error-on-warnings -d "Treat warnings as errors" complete -c crystal -n "__fish_seen_subcommand_from build" -l exclude-warnings -d "Exclude warnings from path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from build" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from build" -l no-codegen -d "Don't do code generation" complete -c crystal -n "__fish_seen_subcommand_from build" -s o -l output -d "Output filename" complete -c crystal -n "__fish_seen_subcommand_from build" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from build" -l release -d "Compile in release mode" complete -c crystal -n "__fish_seen_subcommand_from build" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from build" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from build" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from build" -l single-module -d "Generate a single LLVM module" complete -c crystal -n "__fish_seen_subcommand_from build" -l threads -d "Maximum number of threads to use" complete -c crystal -n "__fish_seen_subcommand_from build" -l target -d "Target triple" complete -c crystal -n "__fish_seen_subcommand_from build" -l verbose -d "Display executed commands" complete -c crystal -n "__fish_seen_subcommand_from build" -l static -d "Link statically" complete -c crystal -n "__fish_seen_subcommand_from build" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "clear_cache" -d "clear the compiler cache" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "docs" -d "generate documentation" complete -c crystal -n "__fish_seen_subcommand_from docs" -l project-name -d "Set project name" complete -c crystal -n "__fish_seen_subcommand_from docs" -l project-version -d "Set project version" complete -c crystal -n "__fish_seen_subcommand_from docs" -l source-refname -d "Set source refname (e.g. git tag, commit hash)" complete -c crystal -n "__fish_seen_subcommand_from docs" -l source-url-pattern -d "Set URL pattern for source code links" complete -c crystal -n "__fish_seen_subcommand_from docs" -s o -l output -d "Set the output directory (default: ./docs)" complete -c crystal -n "__fish_seen_subcommand_from docs" -s f -l format -d "Set the output format (default: html)" -a "html json" complete -c crystal -n "__fish_seen_subcommand_from docs" -l json-config-url -d "Set the URL pointing to a config file (used for discovering versions)" complete -c crystal -n "__fish_seen_subcommand_from docs" -l canonical-base-url -d "Indicate the preferred URL with rel="canonical" link element" complete -c crystal -n "__fish_seen_subcommand_from docs" -s b -l sitemap-base-url -d "Set the sitemap base URL and generates sitemap" complete -c crystal -n "__fish_seen_subcommand_from docs" -l sitemap-priority -d "Set the sitemap priority (default: 1.0)" complete -c crystal -n "__fish_seen_subcommand_from docs" -l sitemap-changefreq -d "Set the sitemap changefreq (default: never) " complete -c crystal -n "__fish_seen_subcommand_from docs" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from docs" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from docs" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from docs" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from docs" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from docs" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from docs" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from docs" -l warnings -d "Which warnings detect (default: all)" -a "all none" -f complete -c crystal -n "__fish_seen_subcommand_from docs" -l error-on-warnings -d "Treat warnings as errors" complete -c crystal -n "__fish_seen_subcommand_from docs" -l exclude-warnings -d "Exclude warnings from path (default: lib)" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "env" -d "print Crystal environment information" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "eval" -d "eval code from args or standard input" complete -c crystal -n "__fish_seen_subcommand_from eval" -s d -l debug -d "Add full symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from eval" -l no-debug -d "Skip any symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from eval" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from eval" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from eval" -l release -d "Compile in release mode" complete -c crystal -n "__fish_seen_subcommand_from eval" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from eval" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from eval" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from eval" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from eval" -l mcpu -d "Target specific cpu type" complete -c crystal -n "__fish_seen_subcommand_from eval" -l mattr -d "Target specific features" complete -c crystal -n "__fish_seen_subcommand_from eval" -l mcmodel -d "Target specific code model" complete -c crystal -n "__fish_seen_subcommand_from eval" -l warnings -d "Which warnings detect. (default: all)" -a "all none" -f complete -c crystal -n "__fish_seen_subcommand_from eval" -l error-on-warnings -d "Treat warnings as errors" complete -c crystal -n "__fish_seen_subcommand_from eval" -l exclude-warnings -d "Exclude warnings from path (default: lib)" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "i interactive" -d "starts interactive Crystal" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "play" -d "starts Crystal playground server" complete -c crystal -n "__fish_seen_subcommand_from play" -s p -l port -d "Runs the playground on the specified port" complete -c crystal -n "__fish_seen_subcommand_from play" -s b -l binding -d "Binds the playground to the specified IP" complete -c crystal -n "__fish_seen_subcommand_from play" -s v -l verbose -d "Display detailed information of executed code" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "run" -d "build and run program" complete -c crystal -n "__fish_seen_subcommand_from run" -s d -l debug -d "Add full symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from run" -l no-debug -d "Skip any symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from run" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from run" -l emit -d "Comma separated list of types of output for the compiler to emit" -a "asm obj llvm-bc llvm-ir" -f complete -c crystal -n "__fish_seen_subcommand_from run" -l x86-asm-syntax -d "X86 dialect for --emit=asm: att (default), intel" -a "att intel" -f complete -c crystal -n "__fish_seen_subcommand_from run" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from run" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from run" -l ll -d "Dump ll to Crystal's cache directory" complete -c crystal -n "__fish_seen_subcommand_from run" -l link-flags -d "Additional flags to pass to the linker" complete -c crystal -n "__fish_seen_subcommand_from run" -l mcpu -d "Target specific cpu type" complete -c crystal -n "__fish_seen_subcommand_from run" -l mattr -d "Target specific features" complete -c crystal -n "__fish_seen_subcommand_from run" -l mcmodel -d "Target specific code model" complete -c crystal -n "__fish_seen_subcommand_from run" -l warnings -d "Which warnings detect. (default: all)" -a "all none" -f complete -c crystal -n "__fish_seen_subcommand_from run" -l error-on-warnings -d "Treat warnings as errors" complete -c crystal -n "__fish_seen_subcommand_from run" -l exclude-warnings -d "Exclude warnings from path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from run" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from run" -l no-codegen -d "Don't do code generation" complete -c crystal -n "__fish_seen_subcommand_from run" -s o -l output -d "Output filename" complete -c crystal -n "__fish_seen_subcommand_from run" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from run" -l release -d "Compile in release mode" complete -c crystal -n "__fish_seen_subcommand_from run" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from run" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from run" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from run" -l single-module -d "Generate a single LLVM module" complete -c crystal -n "__fish_seen_subcommand_from run" -l threads -d "Maximum number of threads to use" complete -c crystal -n "__fish_seen_subcommand_from run" -l verbose -d "Display executed commands" complete -c crystal -n "__fish_seen_subcommand_from run" -l static -d "Link statically" complete -c crystal -n "__fish_seen_subcommand_from run" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "spec" -d "build and run specs" complete -c crystal -n "__fish_seen_subcommand_from spec" -s d -l debug -d "Add full symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from spec" -l no-debug -d "Skip any symbolic debug info" complete -c crystal -n "__fish_seen_subcommand_from spec" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from spec" -l release -d "Compile in release mode" complete -c crystal -n "__fish_seen_subcommand_from spec" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from spec" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from spec" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from spec" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from spec" -l mcpu -d "Target specific cpu type" complete -c crystal -n "__fish_seen_subcommand_from spec" -l mattr -d "Target specific features" complete -c crystal -n "__fish_seen_subcommand_from spec" -l mcmodel -d "Target specific code model" complete -c crystal -n "__fish_seen_subcommand_from spec" -l warnings -d "Which warnings detect. (default: all)" -a "all none" -f complete -c crystal -n "__fish_seen_subcommand_from spec" -l error-on-warnings -d "Treat warnings as errors" complete -c crystal -n "__fish_seen_subcommand_from spec" -l exclude-warnings -d "Exclude warnings from path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from spec" -l link-flags -d "Additional flags to pass to the linker" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "tool" -d "run a tool" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "context" -d "show context for given location" -x complete -c crystal -n "__fish_seen_subcommand_from context" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from context" -s c -l cursor -d "Cursor location with LOC as path/to/file.cr:line:column" complete -c crystal -n "__fish_seen_subcommand_from context" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from context" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from context" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from context" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from context" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from context" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from context" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from context" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "dependencies" -d "show tree of required source files" -x complete -c crystal -n "__fish_seen_subcommand_from context" -s i -l include -d "Include path in output" complete -c crystal -n "__fish_seen_subcommand_from context" -s e -l exclude -d "Exclude path in output" complete -c crystal -n "__fish_seen_subcommand_from context" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from context" -s f -l format -d "Output format 'tree' (default), 'flat', 'dot', or 'mermaid'." -a "tree flat dot mermaid" -f complete -c crystal -n "__fish_seen_subcommand_from context" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from context" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from context" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from context" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from context" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from context" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "expand" -d "show macro expansion for given location" -x complete -c crystal -n "__fish_seen_subcommand_from expand" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from expand" -s c -l cursor -d "Cursor location with LOC as path/to/file.cr:line:column" complete -c crystal -n "__fish_seen_subcommand_from expand" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from expand" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from expand" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from expand" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from expand" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from expand" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from expand" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from expand" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "flags" -d "print all macro 'flag?' values" -x complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "format" -d "format project, directories and/or files" -x complete -c crystal -n "__fish_seen_subcommand_from format" -l check -d "Checks that formatting code produces no changes" complete -c crystal -n "__fish_seen_subcommand_from format" -s i -l include -d "Include path" complete -c crystal -n "__fish_seen_subcommand_from format" -s e -l exclude -d "Exclude path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from format" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from format" -l show-backtrace -d "Show backtrace on a bug (used only for debugging)" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "hierarchy" -d "show type hierarchy" -x complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s e -d "Filter types by NAME regex" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from hierarchy" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "implementations" -d "show implementations for given call in location" -x complete -c crystal -n "__fish_seen_subcommand_from implementations" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from implementations" -s c -l cursor -d "Cursor location with LOC as path/to/file.cr:line:column" complete -c crystal -n "__fish_seen_subcommand_from implementations" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from implementations" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from implementations" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from implementations" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from implementations" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from implementations" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from implementations" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from implementations" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "unreachable" -d "show methods that are never called" -x complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s f -l format -d "Output format text (default), json, csv, codecov" -a "text json csv codecov" -f complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l tallies -d "Print reachable methods and their call counts as well" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l check -d "Exits with error if there is any unreachable code" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s i -l include -d "Include path" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s e -l exclude -d "Exclude path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from unreachable" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "macro_code_coverage" -d "generate a macro code coverage report" -x complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s f -l format -d "Output format codecov (default)" -a "codecov" -f complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s i -l include -d "Include path" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s e -l exclude -d "Exclude path (default: lib)" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from macro_code_coverage" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "types" -d "show type of main variables" -x complete -c crystal -n "__fish_seen_subcommand_from types" -s D -l define -d "Define a compile-time flag" complete -c crystal -n "__fish_seen_subcommand_from types" -s f -l format -d "Output format text (default) or json" -a "text json" -f complete -c crystal -n "__fish_seen_subcommand_from types" -l error-trace -d "Show full error trace" complete -c crystal -n "__fish_seen_subcommand_from types" -l no-color -d "Disable colored output" complete -c crystal -n "__fish_seen_subcommand_from types" -l prelude -d "Use given file as prelude" complete -c crystal -n "__fish_seen_subcommand_from types" -s s -l stats -d "Enable statistics output" complete -c crystal -n "__fish_seen_subcommand_from types" -s p -l progress -d "Enable progress output" complete -c crystal -n "__fish_seen_subcommand_from types" -s t -l time -d "Enable execution time output" complete -c crystal -n "__fish_seen_subcommand_from types" -l stdin-filename -d "Source file name to be read from STDIN" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "help" -d "show help" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -a "version" -d "show version" complete -c crystal -n "not __fish_seen_subcommand_from $crystal_commands" -s v -l version -d "show version" -x ================================================ FILE: etc/completion.zsh ================================================ #compdef crystal _crystal() { _crystal_commands() { local -a commands commands=( "init:generate new crystal project" "build:build an executable" "clear_cache:clear the compiler cache" "docs:generate documentation" "env:print Crystal environment information" "eval:eval code from args or standard input" "play:starts playground server" "run:build and run program" "spec:build and run specs (in spec directory)" "tool:run a tool" "help:show help" "version:show version" ) _describe -t commands 'Crystal command' commands } local -a help_args; help_args=( '(-h --help)'{-h,--help}'[show help]' ) local -a version_args; version_args=( '(-v --version)'{-v,--version}'[show version]' \ ) local -a no_color_args; no_color_args=( '(--no-color)--no-color[disable colored output]' ) local -a prelude_args; prelude_args=( '(--prelude)--prelude[use given file as prelude]' ) local -a exec_args; exec_args=( '(\*)'{-D+,--define=}'[define a compile-time flag]:' \ '(--error-trace)--error-trace[show full error trace]' \ '(-s --stats)'{-s,--stats}'[enable statistics output]' \ '(-t --time)'{-t,--time}'[enable execution time output]' \ '(-p --progress)'{-p,--progress}'[enable progress output]' ) local -a format_args; format_args=( '(-f --format)'{-f,--format}'[output format text (default) or json]:' ) local -a debug_args; debug_args=( '(-d --debug)'{-d,--debug}'[add full symbolic debug info]' \ '(--no-debug)--no-debug[skip any symbolic debug info]' ) local -a release_args; release_args=( '(--release)--release[compile in release mode]' ) local -a cursor_args; cursor_args=( '(-c --cursor)'{-c,--cursor}'[cursor location with LOC as path/to/file.cr:line:column]:LOC' ) local -a include_exclude_args; include_exclude_args=( '(-i --include)'{-i,--include}'[Include path in output]' \ '(-i --exclude)'{-i,--exclude}'[Exclude path in output]' ) local -a stdin_filename_args; stdin_filename_args=( '(--stdin-filename)--stdin-filename[source file name to be read from STDIN]' ) local -a programfile; programfile='*:Crystal File:_files -g "*.cr(.)"' # TODO make 'emit' allow completion with more than one local -a shared_run_build; shared_run_build=( $programfile \ $help_args \ $no_color_args \ $prelude_args \ $format_args \ $exec_args \ $debug_args \ $release_args \ '(--emit)--emit[comma separated list of types of output for the compiler to emit]:foo:(asm llvm-bc llvm-ir obj)' \ '(--x86-asm-syntax)--x86-asm-syntax[X86 dialect for --emit-asm: att (default), intel]:' \ "(--ll)--ll[dump ll to Crystal's cache directory ]" \ '(--link-flags)--link-flags[additional flags to pass to the linker]:' \ '(--mcpu)--mcpu[target specific cpu type]:' \ '(--mattr)--mattr[target specific features]:' \ "(--no-codegen)--no-codegen[don't do code generation]" \ '(-o --output)'{-o,--output}'[output filename]:' \ '(--single-module)--single-module[generate a single llvm module]' \ '(--threads)--threads[maximum number of threads to use]' \ '(--verbose)--verbose[display executed commands]' \ ) # TODO add help text for name and dir _crystal-init() { _arguments \ '1:type:(lib app)' \ && ret=0 } _crystal-build() { _arguments \ $shared_run_build \ '(--cross-compile)--cross-compile[cross-compile FLAGS]:' \ '(--target)--target[target triple]:' \ && ret=0 } _crystal-env() { _arguments \ '(--help)--help[prints help]' \ '1:type:(CRYSTAL_CACHE_DIR CRYSTAL_PATH CRYSTAL_VERSION CRYSTAL_OPTS)' \ && ret=0 } _crystal-eval() { _arguments \ $help_args \ $no_color_args \ $exec_args \ $debug_args \ $release_args \ && ret=0 } _crystal-play() { _arguments \ $programfile \ '(--port)--port[PORT]:' \ '(--binding)--binding[HOST]:' \ '(--verbose)--verbose[display detailed information of executed code]' \ '(-h --help)'{-h,--help}'[show help]' \ && ret=0 } _crystal-run() { _arguments \ $shared_run_build \ && ret=0 } _crystal-spec() { _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $debug_args \ $release_args \ && ret=0 } _crystal-tool() { local curcontext="$curcontext" state line typeset -A opt_args _arguments -C \ ':command:->command' \ '*::options:->options' case $state in (command) local -a commands commands=( "context:show context for given location" "dependencies:show tree of required source files" "expand:show macro expansion for given location" "flags:print all macro 'flag?' values" "format:format project, directories and/or files" "hierarchy:show type hierarchy" "implementations:show implementations for given call in location" "macro_code_coverage:generate a macro code coverage report" "types:show type of main variables" "unreachable:show methods that are never called" ) _describe -t commands 'Crystal tool command' commands _arguments $help_args ;; (options) case $line[1] in (context) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $format_args \ $prelude_args \ $stdin_filename_args \ $cursor_args ;; (dependencies) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ '(-f --format)'{-f,--format}'[output format 'tree' (default), 'flat', 'dot', or 'mermaid']:' \ $prelude_args \ $stdin_filename_args \ $include_exclude_args ;; (expand) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $format_args \ $prelude_args \ $stdin_filename_args \ $cursor_args ;; (flags) _arguments \ $programfile \ $no_color_args \ $help_args ;; (format) _arguments \ $programfile \ $help_args \ $no_color_args \ $include_exclude_args \ '(--check)--check[checks that formatting code produces no changes]' \ '(--show-backtrace)--show-backtrace[show backtrace on a bug (used only for debugging)]' ;; (hierarchy) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $format_args \ $prelude_args \ $stdin_filename_args \ '(-e)-e[filter types by NAME regex]:' ;; (implementations) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $format_args \ $prelude_args \ $cursor_args \ $stdin_filename_args ;; (unreachable) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $include_exclude_args \ '(-f --format)'{-f,--format}'[output format: text (default), json, csv, codecov]:' \ $prelude_args \ '(--check)--check[exits with error if there is any unreachable code]' \ '(--tallies)--tallies[print reachable methods and their call counts as well]' \ $stdin_filename_args ;; (macro_code_coverage) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $include_exclude_args \ '(-f --format)'{-f,--format}'[output format: codecov (default)]:' \ $prelude_args \ $stdin_filename_args ;; (types) _arguments \ $programfile \ $help_args \ $no_color_args \ $exec_args \ $format_args \ $prelude_args \ $stdin_filename_args ;; esac ;; esac } local curcontext=$curcontext ret=1 declare -A opt_args _arguments -C \ $help_args \ $version_args \ '1:sub-command: _alternative "subcommands:sub command:_crystal_commands" "files:file:_files -g \*.cr\(-.\)"' \ '*::arg:->cmd' && ret=0 case $state in (cmd) if (( $CURRENT == 1 )); then else curcontext="${curcontext%:*:*}:crystal-$words[1]:" if ! _call_function ret _crystal-$words[1] ; then _default && ret=0 fi return ret fi ;; esac } _crystal ================================================ FILE: etc/gdb/crystal_formatters.py ================================================ import gdb class CrystalStringPrinter: def __init__(self, val): self.val = val def to_string(self): bytesize = self.val['bytesize'] buf = gdb.selected_inferior().read_memory(self.val['c'].address, bytesize) return buf.tobytes().decode('utf-8', errors='backslashreplace') def display_hint(self): return 'string' class CrystalArrayPrinter: def __init__(self, val): self.val = val def to_string(self): type = self.val.type if type.code == gdb.TYPE_CODE_PTR: type = type.target() return str(type) def children(self): for i in range(int(self.val['size'])): yield str(i), (self.val['buffer'] + i).dereference() def display_hint(self): return 'array' class CrystalReferenceSubPrinter: def __init__(self, name, cls): self.name = name self.enabled = True self.cls = cls def recognize(self, val): type = val.type if type.code == gdb.TYPE_CODE_PTR: type = type.target() typename = type.name if typename is not None: if typename == self.name: return self.cls(val) if typename.startswith(self.name) and typename[len(self.name)] == '(': return self.cls(val) class CrystalPrettyPrinter(gdb.printing.PrettyPrinter): def __init__(self): super(CrystalPrettyPrinter, self).__init__("CrystalStdlib", []) self.subprinters.append(CrystalReferenceSubPrinter("String", CrystalStringPrinter)) self.subprinters.append(CrystalReferenceSubPrinter("Array", CrystalArrayPrinter)) def __call__(self, val): for subprinter in self.subprinters: if subprinter.enabled: instance = subprinter.recognize(val) if instance is not None: return instance gdb.printing.register_pretty_printer( gdb.current_objfile(), CrystalPrettyPrinter(), replace=True) ================================================ FILE: etc/lldb/crystal_formatters.py ================================================ import lldb class CrystalArraySyntheticProvider: def __init__(self, valobj, internal_dict): self.valobj = valobj self.buffer = None self.size = 0 def update(self): if self.valobj.type.is_pointer: self.valobj = self.valobj.Dereference() self.size = int(self.valobj.child[0].value) self.type = self.valobj.type self.buffer = self.valobj.child[3] def num_children(self): size = 0 if self.size is None else self.size return size def get_child_index(self, name): try: return int(name.lstrip('[').rstrip(']')) except: return -1 def get_child_at_index(self,index): if index >= self.size: return None try: elementType = self.buffer.type.GetPointeeType() offset = elementType.size * index return self.buffer.CreateChildAtOffset('[' + str(index) + ']', offset, elementType) except Exception as e: print('Got exception %s' % (str(e))) return None def findType(name, module): cachedTypes = module.GetTypes() for idx in range(cachedTypes.GetSize()): type = cachedTypes.GetTypeAtIndex(idx) if type.name == name: return type return None def CrystalString_SummaryProvider(value, dict): error = lldb.SBError() if value.TypeIsPointerType(): value = value.Dereference() process = value.GetTarget().GetProcess() byteSize = int(value.child[0].value) len = int(value.child[1].value) len = byteSize or len strAddr = value.child[2].load_addr val = process.ReadCStringFromMemory(strAddr, len + 1, error) return '"%s"' % val def __lldb_init_module(debugger, dict): debugger.HandleCommand(r'type synthetic add -l crystal_formatters.CrystalArraySyntheticProvider -x "^Array\(.+\)(\s*\**)?" -w Crystal') debugger.HandleCommand(r'type summary add -F crystal_formatters.CrystalString_SummaryProvider -x "^(String|\(String \| Nil\))(\s*\**)?$" -w Crystal') debugger.HandleCommand(r'type category enable Crystal') ================================================ FILE: etc/msvc/crystal.natvis ================================================ {&c,[bytesize]s8} &c,[bytesize]s8 {{ size={size} }} buffer - offset_to_buffer capacity - offset_to_buffer size buffer {{ size={size} }} entries[i] i += 1 ================================================ FILE: etc/win-ci/build-ffi.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/crystal-lang/libffi.git -Ref v$Version Run-InDirectory $BuildTree { $args = "-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } & $cmake . $args.split(' ') & $cmake --build . --config Release if (-not $?) { Write-Host "Error: Failed to build libffi" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\libffi.lib libs\ffi-dynamic.lib mv -Force $BuildTree\Release\libffi.dll dlls\ } else { mv -Force $BuildTree\Release\libffi.lib libs\ffi.lib } ================================================ FILE: etc/win-ci/build-gc.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [Parameter(Mandatory)] [string] $AtomicOpsVersion, [ValidateSet("Release", "Debug")] [string] $Config = "Release", [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/ivmai/bdwgc.git -Ref v$Version Setup-Git -Path $BuildTree\libatomic_ops -Url https://github.com/ivmai/libatomic_ops.git -Ref v$AtomicOpsVersion Run-InDirectory $BuildTree { $args = "-Dbuild_cord=OFF -Denable_large_config=ON -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } if ($Config -eq "Debug") { $args = "-DCMAKE_SHARED_LINKER_FLAGS=/PDBALTPATH:gc.pdb -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded -DCMAKE_POLICY_DEFAULT_CMP0141=NEW $args" } & $cmake . $args.split(' ') & $cmake --build . --config $Config if (-not $?) { Write-Host "Error: Failed to build libgc" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\$Config\gc.lib libs\gc-dynamic.lib mv -Force $BuildTree\$Config\gc.dll dlls\ if ($Config -eq "Debug") { mv -Force $BuildTree\$Config\gc.pdb dlls\ } } else { mv -Force $BuildTree\$Config\gc.lib libs\ } ================================================ FILE: etc/win-ci/build-iconv.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Invoke-WebRequest "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-${Version}.tar.gz" -OutFile libiconv.tar.gz tar -xzf libiconv.tar.gz mv libiconv-* $BuildTree rm libiconv.tar.gz Run-InDirectory $BuildTree { $env:CHERE_INVOKING = 1 [System.IO.File]::WriteAllText("src\Makefile.in", [System.IO.File]::ReadAllText("src\Makefile.in").Replace("chmod 777 .", "true")) & 'C:\cygwin64\bin\bash.exe' --login "$PSScriptRoot\cygwin-build-iconv.sh" "$(if ($Dynamic) { 1 })" if (-not $?) { Write-Host "Error: Failed to build libiconv" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\iconv\lib\iconv.dll.lib libs\iconv-dynamic.lib mv -Force $BuildTree\iconv\bin\iconv-2.dll dlls\ } else { mv -Force $BuildTree\iconv\lib\iconv.lib libs\ } ================================================ FILE: etc/win-ci/build-llvm.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [Parameter(Mandatory)] [string[]] $TargetsToBuild, [switch] $Dynamic ) if (-not $Dynamic) { Write-Host "Error: Building LLVM as a static library is not supported yet" -ForegroundColor Red Exit 1 } . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/llvm/llvm-project.git -Ref llvmorg-$Version Run-InDirectory $BuildTree\build { $args = "-Thost=x64 -DLLVM_TARGETS_TO_BUILD=$($TargetsToBuild -join ';') -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ZSTD=OFF" if ($Dynamic) { $args = "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL $args" } else { $args = "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DLLVM_BUILD_LLVM_C_DYLIB=OFF $args" } & $cmake ..\llvm $args.split(' ') & $cmake --build . --config Release --target llvm-config --target LLVM-C if (-not $?) { Write-Host "Error: Failed to build LLVM" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\build\Release\lib\LLVM-C.lib libs\llvm-dynamic.lib mv -Force $BuildTree\build\Release\bin\LLVM-C.dll dlls\ } else { # TODO (probably never) } Add-Content libs\llvm_VERSION $(& "$BuildTree\build\Release\bin\llvm-config.exe" --version) Add-Content libs\llvm_VERSION $(& "$BuildTree\build\Release\bin\llvm-config.exe" --targets-built) Add-Content libs\llvm_VERSION $(& "$BuildTree\build\Release\bin\llvm-config.exe" --system-libs) ================================================ FILE: etc/win-ci/build-mpir.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/BrianGladman/mpir.git -Ref dc82b0475dea84d5338356e49176c40be03a5bdf # master@{2023-02-10} Run-InDirectory $BuildTree { $vsVersion = "vs$((& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -property displayName) -replace '.*\b\d\d(\d\d)\b.*', '$1')" echo ' $(MsbuildThisFileDirectory)\Override.props ' > 'msvc\Directory.Build.props' echo ' None false false ' > 'msvc\Override.props' if ($Dynamic) { MSBuild.exe /p:Platform=x64 /p:Configuration=Release "msvc\$vsVersion\dll_mpir_gc\dll_mpir_gc.vcxproj" } else { MSBuild.exe /p:Platform=x64 /p:Configuration=Release "msvc\$vsVersion\lib_mpir_gc\lib_mpir_gc.vcxproj" } if (-not $?) { Write-Host "Error: Failed to build MPIR" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\dll\x64\Release\mpir.lib libs\mpir-dynamic.lib mv -Force $BuildTree\dll\x64\Release\mpir.dll dlls\ } else { mv -Force $BuildTree\lib\x64\Release\mpir.lib libs\ } ================================================ FILE: etc/win-ci/build-openssl.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/openssl/openssl -Ref openssl-$Version Run-InDirectory $BuildTree { Replace-Text Configurations\10-main.conf '/Zi /Fdossl_static.pdb' '' Replace-Text Configurations\10-main.conf '"/nologo /debug"' '"/nologo /debug:none"' if ($Dynamic) { perl Configure VC-WIN64A no-tests } else { perl Configure VC-WIN64A /MT -static no-tests } nmake if (-not $?) { Write-Host "Error: Failed to build OpenSSL" -ForegroundColor Red Exit 1 } } if ($Dynamic) { $major = $Version -replace '\..*', '' mv -Force $BuildTree\libcrypto.lib libs\crypto-dynamic.lib mv -Force $BuildTree\libssl.lib libs\ssl-dynamic.lib mv -Force $BuildTree\libcrypto-$major-x64.dll dlls\ mv -Force $BuildTree\libssl-$major-x64.dll dlls\ } else { mv -Force $BuildTree\libcrypto.lib libs\crypto.lib mv -Force $BuildTree\libssl.lib libs\ssl.lib } [IO.File]::WriteAllLines("libs\openssl_VERSION", $Version) ================================================ FILE: etc/win-ci/build-pcre.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) function Find-7Zip { $Path = Get-Command "7z" -CommandType Application -TotalCount 1 -ErrorAction SilentlyContinue if ($Path) { return $Path.Path } $Path = "$env:ProgramFiles\7-Zip\7z.exe" if (Test-Path -Path $Path -PathType Leaf) { return $Path } $Path = "${env:ProgramFiles(x86)}\7-Zip\7z.exe" if (Test-Path -Path $Path -PathType Leaf) { return $Path } Write-Host "Error: Cannot locate 7-Zip executable" -ForegroundColor Red Exit 1 } . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Invoke-WebRequest https://cs.stanford.edu/pub/exim/pcre/pcre-$Version.zip -OutFile pcre.zip & (Find-7Zip) x pcre.zip mv pcre-* $BuildTree rm pcre.zip Run-InDirectory $BuildTree { $args = "-DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF -DPCRE_BUILD_PCRECPP=OFF -DPCRE_SUPPORT_JIT=ON -DPCRE_SUPPORT_UNICODE_PROPERTIES=ON -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DPCRE_STATIC_RUNTIME=ON $args" } & $cmake . $args.split(' ') & $cmake --build . --config Release if (-not $?) { Write-Host "Error: Failed to build PCRE" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\pcre.lib libs\pcre-dynamic.lib mv -Force $BuildTree\Release\pcre.dll dlls\ } else { mv -Force $BuildTree\Release\pcre.lib libs\ } ================================================ FILE: etc/win-ci/build-pcre2.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/PCRE2Project/pcre2.git -Ref pcre2-$Version Run-InDirectory $BuildTree { & $git submodule update --init $args = "-DPCRE2_BUILD_PCRE2GREP=OFF -DPCRE2_BUILD_TESTS=OFF -DPCRE2_SUPPORT_UNICODE=ON -DPCRE2_SUPPORT_JIT=ON -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } & $cmake . $args.split(' ') & $cmake --build . --config Release if (-not $?) { Write-Host "Error: Failed to build PCRE2" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\pcre2-8.lib libs\pcre2-8-dynamic.lib mv -Force $BuildTree\Release\pcre2-8.dll dlls\ } else { mv -Force $BuildTree\Release\pcre2-8-static.lib libs\pcre2-8.lib } ================================================ FILE: etc/win-ci/build-xml2.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://gitlab.gnome.org/GNOME/libxml2.git -Ref v$Version Run-InDirectory $BuildTree { $args = "-DLIBXML2_WITH_TESTS=OFF -DLIBXML2_WITH_PROGRAMS=OFF -DLIBXML2_WITH_HTTP=OFF -DLIBXML2_WITH_FTP=OFF -DLIBXML2_WITH_ICONV=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_ZLIB=OFF -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } & $cmake . $args.split(' ') & $cmake --build . --config Release if (-not $?) { Write-Host "Error: Failed to build libxml2" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\libxml2.lib libs\xml2-dynamic.lib mv -Force $BuildTree\Release\libxml2.dll dlls\ } else { mv -Force $BuildTree\Release\libxml2s.lib libs\xml2.lib } [IO.File]::WriteAllLines("libs\libxml_VERSION", $Version) ================================================ FILE: etc/win-ci/build-yaml.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/yaml/libyaml.git -Ref $Version Run-InDirectory $BuildTree { $args = "-DBUILD_TESTING=OFF -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } & $cmake . $args.split(' ') & $cmake --build . --config Release if (-not $?) { Write-Host "Error: Failed to build libyaml" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\yaml.lib libs\yaml-dynamic.lib mv -Force $BuildTree\Release\yaml.dll dlls\ } else { mv -Force $BuildTree\Release\yaml.lib libs\ } ================================================ FILE: etc/win-ci/build-z.ps1 ================================================ param( [Parameter(Mandatory)] [string] $BuildTree, [Parameter(Mandatory)] [string] $Version, [switch] $Dynamic ) . "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1" [void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force) Setup-Git -Path $BuildTree -Url https://github.com/madler/zlib.git -Ref v$Version Run-InDirectory $BuildTree { $args = "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF" if ($Dynamic) { $args = "-DBUILD_SHARED_LIBS=ON $args" } else { $args = "-DBUILD_SHARED_LIBS=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded $args" } & $cmake . $args.split(' ') & $cmake --build . --target $(if ($Dynamic) { 'zlib' } else { 'zlibstatic' }) --config Release if (-not $?) { Write-Host "Error: Failed to build zlib" -ForegroundColor Red Exit 1 } } if ($Dynamic) { mv -Force $BuildTree\Release\zlib.lib libs\z-dynamic.lib mv -Force $BuildTree\Release\zlib1.dll dlls\ } else { mv -Force $BuildTree\Release\zlibstatic.lib libs\z.lib } ================================================ FILE: etc/win-ci/crystal.iss ================================================ #define MyAppName "Crystal" #define VersionFile FileOpen("portable\src\VERSION") #define MyAppVersion FileRead(VersionFile) #define MyAppVersionNum StringChange(MyAppVersion, "-dev", "") #expr FileClose(VersionFile) #define MyAppPublisher "Manas Technology Solutions" #define MyAppURL "https://crystal-lang.org/" #define MyAppExeName "crystal.exe" #define MyAppCopyright GetFileCopyright("portable\" + MyAppExeName) #define MyAppAssocName MyAppName + " Source File" #define MyAppAssocExt ".cr" #define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt #define MajorNum 0 #define MinorNum 0 #expr UnpackVersionComponents(StrToVersion(MyAppVersionNum), MajorNum, MinorNum, null, null) [Setup] AppId={{7C307DDF-447E-46C5-BB3B-47A6F652D7C8} AppName={#MyAppName} x86_64-windows-msvc AppVersion={#MyAppVersion} AppCopyright={#MyAppCopyright} VersionInfoVersion={#MyAppVersionNum} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} ArchitecturesAllowed=x64 ArchitecturesInstallIn64BitMode=x64 DefaultDirName={autopf}\{#MyAppName} OutputBaseFilename=crystal-setup LicenseFile=portable\LICENSE.txt ChangesEnvironment=yes ChangesAssociations=yes DefaultGroupName={#MyAppName} {#MyAppVersion} AllowNoIcons=yes PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog Compression=lzma SolidCompression=yes WizardStyle=modern WizardImageFile=crystal.bmp WizardSmallImageFile=crystal_small.bmp DisableWelcomePage=no SetupMutex={#MyAppName}SetupMutex [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Types] Name: "full"; Description: "Full installation" Name: "minimal"; Description: "Minimal installation" Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] Name: "main"; Description: "Crystal compiler"; Types: full minimal custom; Flags: fixed Name: "shards"; Description: "Shards dependency manager"; Types: full Name: "pdb"; Description: "Debug symbols"; Types: full Name: "samples"; Description: "Sample programs"; Types: full Name: "docs"; Description: "Offline standard library documentation"; Types: full [Tasks] Name: addtopath; Description: "Add Crystal's directory to the &PATH environment variable"; Flags: checkedonce Name: association; Description: "{cm:AssocFileExtension,Crystal,.cr}"; Flags: unchecked [Files] Source: "portable\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Components: main Source: "portable\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion; Components: main Source: "portable\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: main Source: "portable\src\*"; DestDir: "{app}\src"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: main Source: "portable\README.md"; DestDir: "{app}"; Flags: ignoreversion isreadme; Components: main Source: "portable\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion; Components: main Source: "portable\shards.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: shards Source: "portable\crystal.pdb"; DestDir: "{app}"; Flags: ignoreversion; Components: pdb Source: "portable\shards.pdb"; DestDir: "{app}"; Flags: ignoreversion; Components: pdb and shards Source: "portable\examples\*"; DestDir: "{app}\examples"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: samples Source: "portable\docs\*"; DestDir: "{app}\docs"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs [UninstallDelete] Type: filesandordirs; Name: "{localappdata}\crystal\cache" [Registry] Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}"; ValueType: string; ValueName: "PerceivedType"; ValueData: "text"; Flags: uninsdeletevalue Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".cr"; ValueData: ""; Flags: uninsdeletekey [Icons] Name: "{group}\Crystal Book"; Filename: "https://crystal-lang.org/reference/{#MajorNum}.{#MinorNum}/index.html" Name: "{group}\Crystal Standard Library API"; Filename: "{app}\docs\index.html"; Components: docs Name: "{group}\Crystal Standard Library API"; Filename: "https://crystal-lang.org/api/{#MyAppVersion}/index.html"; Components: not docs Name: "{group}\Official Website"; Filename: "https://crystal-lang.org/" Name: "{group}\GitHub Repository"; Filename: "https://github.com/crystal-lang/crystal" [Code] const CLSID_SetupConfiguration = '{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}'; const Win10SDK64 = 'SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0'; const Win10SDK32 = 'SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0'; type ISetupInstance = interface(IUnknown) '{B41463C3-8866-43B5-BC33-2B0676F7F42E}' procedure GetInstanceId; procedure GetInstallDate; procedure GetInstallationName; function GetInstallationPath(out installationPath: WideString): HResult; procedure GetInstallationVersion; procedure GetDisplayName; procedure GetDescription; procedure ResolvePath; end; IEnumSetupInstances = interface(IUnknown) '{6380BCFF-41D3-4B2E-8B2E-BF8A6810C848}' function Next(celt: DWord; out rgelt: ISetupInstance; out pceltFetched: DWord): HResult; procedure Skip; procedure Reset; procedure Clone; end; ISetupConfiguration = interface(IUnknown) '{42843719-DB4C-46C2-8E7C-64F1816EFD5B}' function EnumInstances(out enumInstances: IEnumSetupInstances): HResult; end; IClassFactory = interface(IUnknown) '{00000001-0000-0000-C000-000000000046}' function CreateInstance(unkOuter: IUnknown; riid: TGUID; out object: IUnknown): HResult; procedure LockServer; end; function HasMSVC: Boolean; var config: ISetupConfiguration; enumSetup: IEnumSetupInstances; count: DWord; setup: ISetupInstance; setupPath: WideString; msvcVersion: AnsiString; hresult: HResult; begin result := False; try config := ISetupConfiguration(CreateComObject(StringToGuid(CLSID_SetupConfiguration))); except exit; end; OleCheck(config.EnumInstances(enumSetup)); While True do begin hresult := enumSetup.Next(1, setup, count); OleCheck(hresult); if hresult = 1 then Break; hresult := setup.GetInstallationPath(setupPath); if hresult <> 0 then Continue; if not LoadStringFromFile(setupPath + '\VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt', msvcVersion) then Continue; if not FileExists(setupPath + '\VC\Tools\MSVC\' + TrimRight(msvcVersion) + '\bin\Hostx64\x64\cl.exe') then Continue; Log('MSVC location: ' + setupPath + '\VC\Tools\MSVC\' + TrimRight(msvcVersion)); result := True; exit; end; end; function HasWinSDKAt(const rootKey: Integer; const subKey: String): Boolean; var installationFolder: String; productVersion: String; begin result := False; if RegQueryStringValue(rootKey, subKey, 'InstallationFolder', installationFolder) then if RegQueryStringValue(rootKey, subKey, 'ProductVersion', productVersion) then if FileExists(installationFolder + '\Include\' + productVersion + '.0\um\winsdkver.h') then begin Log('Windows SDK location: ' + installationFolder + '\Lib\' + productVersion); result := True; end; end; function HasWinSDK: Boolean; begin result := HasWinSDKAt(HKEY_LOCAL_MACHINE, Win10SDK64) or HasWinSDKAt(HKEY_LOCAL_MACHINE, Win10SDK32) or HasWinSDKAt(HKEY_CURRENT_USER, Win10SDK64) or HasWinSDKAt(HKEY_CURRENT_USER, Win10SDK32); end; function HasVCRedist: Boolean; var regValue: Cardinal; begin result := False; if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64', 'Installed', regValue) then if regValue <> 0 then result := True; end; { Adopted from https://stackoverflow.com/a/46609047 } procedure EnvAddPath(Path: string; IsSystem: Boolean); var Paths: string; Status: Boolean; begin if IsSystem then Status := RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', Paths) else Status := RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Paths); if not Status then Paths := ''; if Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';') > 0 then exit; Paths := Paths + ';' + Path + ';'; if IsSystem then RegWriteStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', Paths) else RegWriteStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Paths); end; procedure EnvRemovePath(Path: string; IsSystem: Boolean); var Paths: string; Status: Boolean; P: Integer; begin if IsSystem then Status := RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', Paths) else Status := RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Paths); if not Status then exit; P := Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';'); if P = 0 then exit; Delete(Paths, P - 1, Length(Path) + 1); if IsSystem then RegWriteStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', Paths) else RegWriteStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Paths); end; function GetUninstallString(): String; var sUnInstPath: String; sUnInstallString: String; begin sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); sUnInstallString := ''; if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); result := sUnInstallString; end; procedure InitializeWizard; var updatingPage: TOutputMsgWizardPage; begin if GetUninstallString() <> '' then updatingPage := CreateOutputMsgPage( wpSelectTasks, 'Pre-Install Checks', 'A previous Crystal installation already exists.', 'Setup has detected a previous installation of Crystal; it will be uninstalled before the new version is installed. ' + 'This ensures that requiring Crystal files will not pick up any leftover files from the previous version.'#13#13 + 'To use multiple Crystal installations side-by-side, the portable packages for the extra versions must be downloaded manually.'); end; procedure CurStepChanged(CurStep: TSetupStep); var uninstallString: String; exitCode: Integer; begin case CurStep of ssInstall: begin uninstallString := GetUninstallString(); if uninstallString <> '' then if not Exec(RemoveQuotes(uninstallString), '/VERYSILENT /NORESTART /SUPPRESSMSGBOXES', '', SW_HIDE, ewWaitUntilTerminated, exitCode) then begin SuppressibleMsgBox('Failed to remove the previous Crystal installation. Setup will now exit.', mbCriticalError, MB_OK, IDOK); Abort; end; end; ssPostInstall: begin if (not HasVCRedist) and (IDYES = SuppressibleTaskDialogMsgBox( 'Install Visual C++ Redistributable', 'Setup is unable to detect a copy of the Visual C++ 2015 Redistributable (x64) or newer on this machine. ' + 'The runtime libraries are needed by dynamically linked executables, including the compiler itself. ' + 'If you select "Agree", the installer will proceed to download: '#13#10#13#10 + 'https://aka.ms/vs/17/release/vc_redist.x64.exe'#13#10#13#10 + 'and then run:'#13#10#13#10 + 'VC_redist.x64.exe /passive /norestart'#13#10#13#10 + 'Would you like to install the Visual C++ Redistributable now?', mbInformation, MB_YESNO, ['Agree', 'Decline'], IDYES, IDYES)) then begin DownloadTemporaryFile('https://aka.ms/vs/17/release/vc_redist.x64.exe', 'VC_redist.x64.exe', '', nil); if not Exec(ExpandConstant('{tmp}\VC_redist.x64.exe'), '/passive /norestart', '', SW_SHOW, ewWaitUntilTerminated, exitCode) then SuppressibleMsgBox('Failed to install the Visual C++ Redistributable.', mbError, MB_OK, IDOK); end; if (not HasMSVC) and (IDYES = SuppressibleTaskDialogMsgBox( 'Install MSVC Build Tools', 'Setup is unable to detect a copy of the Build Tools for Visual Studio 2017 or newer on this machine. ' + 'The MSVC Build Tools are required to link Crystal programs into Windows executables. ' + 'If you select "Agree", the installer will proceed to download: '#13#10#13#10 + 'https://aka.ms/vs/17/release/vs_BuildTools.exe'#13#10#13#10 + 'and then run:'#13#10#13#10 + 'vs_BuildTools.exe --passive --norestart --wait --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64'#13#10#13#10 + 'Would you like to install the MSVC Build Tools now? ' + 'Note that you may modify your installation later using the Visual Studio Installer.', mbInformation, MB_YESNO, ['Agree', 'Decline'], IDYES, IDYES)) then begin DownloadTemporaryFile('https://aka.ms/vs/17/release/vs_BuildTools.exe', 'vs_BuildTools.exe', '', nil); if not Exec( ExpandConstant('{tmp}\vs_BuildTools.exe'), '--passive --norestart --wait --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '', SW_SHOW, ewWaitUntilTerminated, exitCode ) then SuppressibleMsgBox('Failed to install the Build Tools for Visual Studio.', mbError, MB_OK, IDOK); end; if (not HasWinSDK) and (IDYES = SuppressibleTaskDialogMsgBox( 'Install Windows SDK', 'Setup is unable to detect a copy of the Windows 10 SDK or newer on this machine. ' + 'The Crystal runtime and standard library rely on the Win32 libraries to interface with the Windows system. ' + 'If you select "Agree", the installer will proceed to download: '#13#10#13#10 + 'https://aka.ms/vs/17/release/vs_BuildTools.exe'#13#10#13#10 + 'and then run:'#13#10#13#10 + 'vs_BuildTools.exe --passive --norestart --wait --add Microsoft.VisualStudio.Component.Windows11SDK.22621'#13#10#13#10 + 'Would you like to install the Windows SDK now? ' + 'Note that you may modify your installation later using the Visual Studio Installer.', mbInformation, MB_YESNO, ['Agree', 'Decline'], IDYES, IDYES)) then begin DownloadTemporaryFile('https://aka.ms/vs/17/release/vs_BuildTools.exe', 'vs_BuildTools.exe', '', nil); if not Exec( ExpandConstant('{tmp}\vs_BuildTools.exe'), '--passive --norestart --wait --add Microsoft.VisualStudio.Component.Windows11SDK.22621', '', SW_SHOW, ewWaitUntilTerminated, exitCode ) then SuppressibleMsgBox('Failed to install the Windows SDK.', mbError, MB_OK, IDOK); end; if WizardIsTaskSelected('addtopath') then EnvAddPath(ExpandConstant('{app}'), IsAdminInstallMode()); end; end; end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); begin if CurUninstallStep = usPostUninstall then EnvRemovePath(ExpandConstant('{app}'), IsAdminInstallMode()); end; ================================================ FILE: etc/win-ci/cygwin-build-iconv.sh ================================================ #!/bin/sh # shellcheck disable=SC2155 set -e Dynamic=$1 export PATH="$(pwd)/build-aux:$PATH" export CC="$(pwd)/build-aux/compile cl -nologo" export CXX="$(pwd)/build-aux/compile cl -nologo" export AR="$(pwd)/build-aux/ar-lib lib" export LD="link" export NM="dumpbin -symbols" export STRIP=":" export RANLIB=":" if [ -n "$Dynamic" ]; then export CFLAGS="-MD" export CXXFLAGS="-MD" enable_shared=yes enable_static=no else export CFLAGS="-MT" export CXXFLAGS="-MT" enable_shared=no enable_static=yes # GNU libiconv appears to define `BUILDING_DLL` unconditionally, so the static # library contains `/EXPORT` directives that make any executable also export # the iconv symbols, which we don't want find . '(' -name '*.h' -or -name '*.h.build.in' ')' -print0 | xargs -0 -I{} sed -i 's/__declspec(dllexport)//' '{}' fi export CPPFLAGS="-O2 -D_WIN32_WINNT=_WIN32_WINNT_WIN7 -I$(pwd)/iconv/include" export LDFLAGS="-L$(pwd)/iconv/lib" ./configure --host=x86_64-w64-mingw32 --prefix="$(pwd)/iconv" --enable-shared="${enable_shared}" --enable-static="${enable_static}" make make install ================================================ FILE: etc/win-ci/setup.ps1 ================================================ function Run-InDirectory { param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [scriptblock] $ScriptBlock ) [void](New-Item -Name $Path -ItemType Directory -Force) Push-Location $Path [Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath try { & $ScriptBlock } finally { Pop-Location [Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath } } function Find-Git { $Path = Get-Command "git" -CommandType Application -TotalCount 1 -ErrorAction SilentlyContinue if ($Path) { return $Path.Path } $Path = "$env:ProgramFiles\Git\cmd\git.exe" if (Test-Path -Path $Path -PathType Leaf) { return $Path } Write-Host "Error: Cannot locate Git executable" -ForegroundColor Red Exit 1 } function Find-CMake { $Path = Get-Command "cmake" -CommandType Application -TotalCount 1 -ErrorAction SilentlyContinue if ($Path) { return $Path.Path } $Path = "$env:ProgramFiles\CMake\bin\cmake.exe" if (Test-Path -Path $Path -PathType Leaf) { return $Path } Write-Host "Error: Cannot locate CMake executable" -ForegroundColor Red Exit 1 } function Setup-Git { param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [string] $Url, [string] $Ref = $null ) if (-not (Test-Path $Path)) { $args = "clone", "--config", "core.autocrlf=false", $Url, $Path Write-Host "$git $args" -ForegroundColor Cyan & $git $args if (-not $?) { Write-Host "Error: Failed to clone Git repository" -ForegroundColor Red Exit 1 } } if ($Ref) { Run-InDirectory $Path { Write-Host "$git checkout $Ref" -ForegroundColor Cyan & $git checkout $Ref } } } function Replace-Text { param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [string] $Pattern, [Parameter(Mandatory)] [AllowEmptyString()] [string] $Replacement ) $content = [System.IO.File]::ReadAllText($Path).Replace($Pattern, $Replacement) [System.IO.File]::WriteAllText($Path, $content) } $git = Find-Git $cmake = Find-CMake [void](New-Item -Name libs -ItemType Directory -Force) [void](New-Item -Name dlls -ItemType Directory -Force) ================================================ FILE: lib/.shards.info ================================================ --- version: 1.0 shards: markd: git: https://github.com/icyleaf/markd.git version: 0.5.0 reply: git: https://github.com/i3oris/reply.git version: 0.3.1+git.commit.13f7eba083f138dd063c68b859c8e315f44fb523 sanitize: git: https://github.com/straight-shoota/sanitize.git version: 0.1.0+git.commit.75c141b619c77956e88f557149566cd28876398b ================================================ FILE: man/crystal.1 ================================================ '\" t .\" Title: crystal .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.23 .\" Date: 2025-02-14 .\" Manual: Crystal Compiler Command Line Reference Guide .\" Source: crystal 1.16.0-dev .\" Language: English .\" .TH "CRYSTAL" "1" "2025-02-14" "crystal 1.16.0\-dev" "Crystal Compiler Command Line Reference Guide" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 .nh .ad l .de URL \fI\\$2\fP <\\$1>\\$3 .. .als MTO URL .if \n[.g] \{\ . mso www.tmac . am URL . ad l . . . am MTO . ad l . . . LINKSTYLE blue R < > .\} .SH "NAME" crystal \- compiler for the Crystal language .SH "SYNOPSIS" .sp \fBcrystal\fP command [switches] programfile \(em [arguments] .SH "DESCRIPTION" .sp Crystal is a statically type\-checked programming language. It was created with the beauty of Ruby and the performance of C in mind. .SH "USAGE" .sp You can compile and run a program by invoking the compiler with a single filename: .sp .if n .RS 4 .nf .fam C crystal some_program.cr .fam .fi .if n .RE .sp Crystal files usually end with the .cr extension, though this is not mandatory. .sp Alternatively you can use the run command: .sp .if n .RS 4 .nf .fam C crystal run some_program.cr .fam .fi .if n .RE .sp To create an executable use the build command: .sp .if n .RS 4 .nf .fam C crystal build some_program.cr .fam .fi .if n .RE .sp This will create an executable named "some_program". .sp Note that by default the generated executables are not fully optimized. To turn optimizations on, use the \fB\-\-release\fP flag: .sp .if n .RS 4 .nf .fam C crystal build \-\-release some_program.cr .fam .fi .if n .RE .sp Make sure to always use \fB\-\-release\fP for production\-ready executables and when performing benchmarks. .sp The optimizations are not turned on by default because the compile times are much faster without them and the performance of the program is still pretty good without them, so it allows to use the \fBcrystal\fP command almost to be used as if it was an interpreter. .SH "OPTIONS" .sp The \fBcrystal\fP command accepts the following options .SS "init" .sp \fBinit\fP TYPE [DIR | NAME DIR] .sp Generates a new Crystal project. .sp TYPE is one of: .sp \fBlib\fP Creates a library skeleton .br \fBapp\fP Creates an application skeleton .sp This initializes the lib/app project folder as a git repository, with a license file, a README file, a shard.yml for use with shards (the Crystal dependency manager), a .gitignore file, and src and spec folders. .sp DIR \- directory where project will be generated .sp NAME \- name of project to be generated (default: basename of DIR) .sp Options: .sp \fB\-f, \-\-force\fP .RS 4 Force overwrite existing files. .RE .sp \fB\-s, \-\-skip\-existing\fP .RS 4 Skip existing files. .RE .SS "build" .sp \fBbuild\fP [options] [programfile] [\-\-] [arguments] .sp Compile program. .sp Options: .sp \fB\-\-cross\-compile\fP .RS 4 Generate an object file for cross compilation and prints the command to build the executable. The object file should be copied to the target system and the printed command should be executed there. This flag mainly exists for porting the compiler to new platforms, where possible run the compiler on the target platform directly. .RE .sp \fB\-d\fP, \fB\-\-debug\fP .RS 4 Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. .RE .sp \fB\-\-no\-debug\fP .RS 4 Generate the output without any symbolic debug symbols. .RE .sp \fB\-D\fP \fIFLAG\fP, \fB\-\-define\fP \fIFLAG\fP .RS 4 Define a compile\-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with \fB\-\-target\-triple\fP or the hosts default, if none is given. .RE .sp \fB\-\-emit\fP [asm|llvm\-bc|llvm\-ir|obj] .RS 4 Comma separated list of types of output for the compiler to emit. You can use this to see the generated LLVM IR, LLVM bitcode, assembly, and object files. .RE .sp \fB\-\-x86\-asm\-syntax\fP [att|intel] .RS 4 Select the assembly dialect for \fB\-\-emit=asm\fP. The default is \f(CRatt\fP, which stands for the AT&T syntax supported by tools like the GNU Assembler. \f(CRintel\fP selects the Intel syntax which is preferred for Windows tools. .RE .sp \fB\-\-frame\-pointers\fP [auto|always|non\-leaf] .RS 4 Control the preservation of frame pointers. The default value, \f(CR\-\-frame\-pointers=auto\fP, will preserve frame pointers on debug builds and try to omit them on release builds (certain platforms require them to stay enabled). \f(CR\-\-frame\-pointers=always\fP will always preserve them, and non\-leaf will only force their preservation on non\-leaf functions. .RE .sp \fB\-f\fP text|json, \fB\-\-format\fP text|json .RS 4 Format of output. Defaults to text. The json format can be used to get a more parser\-friendly output. .RE .sp \fB\-\-error\-trace\fP .RS 4 Show full error trace. Disabled by default, as the full trace usually makes error messages less readable and may not always deliver relevant information. .RE .sp \fB\-\-ll\fP .RS 4 Dump LLVM assembly file to output directory. .RE .sp \fB\-\-link\-flags\fP \fIFLAGS\fP .RS 4 Pass additional flags to the linker. Though you can specify those flags on the source code, this is useful for passing environment specific information directly to the linker, like non\-standard library paths or names. For more information on specifying linker flags on source, you can read the "C bindings" section of the documentation available on the official web site. .RE .sp \fB\-\-mcpu\fP \fICPU\fP .RS 4 Specify a specific CPU to generate code for. This will pass a \-mcpu flag to LLVM, and is only intended to be used for cross\- compilation. For a list of available CPUs, pass \-\-mcpu help when building any Crystal source code. Passing \-\-mcpu native will pass the host CPU name to tune performance for the host. .RE .sp \fB\-\-mattr\fP \fICPU\fP .RS 4 Override or control specific attributes of the target, such as whether SIMD operations are enabled or not. The default set of attributes is set by the current CPU. This will pass a \-mattr flag to LLVM, and is only intended to be used for cross\-compilation. For a list of available attributes, invoke "llvm\-as < /dev/null | llc \-march=xyz \-mattr=help". .RE .sp \fB\-\-mcmodel\fP default|kernel|tiny|small|medium|large .RS 4 Specifies a specific code model to generate code for. This will pass a \-\-code\-model flag to LLVM. .RE .sp \fB\-\-no\-color\fP .RS 4 Disable colored output. .RE .sp \fB\-\-no\-codegen\fP .RS 4 Don\(cqt do code generation, just parse the file. .RE .sp \fB\-o\fP .RS 4 Specify filename of output. .RE .sp \fB\-\-prelude\fP .RS 4 Specify prelude to use. The default one initializes the garbage collector. You can also use \-\-prelude=empty to use no preludes. This can be useful for checking code generation for a specific source code file. .RE .sp \fB\-O\fP \fILEVEL\fP .RS 4 Optimization mode: 0 (default), 1, 2, 3. See \fBOPTIMIZATIONS\fP for details. .RE .sp \fB\-\-release\fP .RS 4 Compile in release mode. Equivalent to \fB\-O3 \-\-single\-module\fP .RE .sp \fB\-s\fP, \fB\-\-stats\fP .RS 4 Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. .RE .sp \fB\-p\fP, \fB\-\-progress\fP .RS 4 Print statistics about the progress for the current build. .RE .sp \fB\-t\fP, \fB\-\-time\fP .RS 4 Print statistics about the execution time. .RE .sp \fB\-\-single\-module\fP .RS 4 Generate a single LLVM module. By default, one LLVM module is created for each type in a program. \fB\-\-release\fP implies this option. .RE .sp \fB\-\-threads\fP \fINUM\fP .RS 4 Maximum number of threads to use for code generation. The default is 8 threads. .RE .sp \fB\-\-target\fP \fITRIPLE\fP .RS 4 Enable target triple; intended to use for cross\-compilation. See llvm documentation for more information about target triple. .RE .sp \fB\-\-verbose\fP .RS 4 Display the commands executed by the system. .RE .sp \fB\-\-static\fP .RS 4 Create a statically linked executable. .RE .sp \fB\-\-stdin\-filename\fP \fIFILENAME\fP .RS 4 Source file name to be read from STDIN. .RE .SS "docs" .sp Generate documentation from comments using a subset of markdown. The output is saved in html format on the created docs/ folder. More information about documentation conventions can be found at \c .URL "https://crystal\-lang.org/docs/conventions/documenting_code.html" "" "." .sp Options: .sp \fB\-\-project\-name\fP \fINAME\fP .RS 4 Set the project name. The default value is extracted from shard.yml if available. .sp In case no default can be found, this option is mandatory. .RE .sp \fB\-\-project\-version\fP \fIVERSION\fP .RS 4 Set the project version. The default value is extracted from current git commit or shard.yml if available. .sp In case no default can be found, this option is mandatory. .RE .sp \fB\-\-json\-config\-url\fP \fIURL\fP .RS 4 Set the URL pointing to a config file (used for discovering versions). .RE .sp \fB\-\-source\-refname\fP \fIREFNAME\fP .RS 4 Set source refname (e.g. git tag, commit hash). The default value is extracted from current git commit if available. .sp If this option is missing and can\(cqt be automatically determined, the generator can\(cqt produce source code links. .RE .sp \fB\-\-source\-url\-pattern\fP \fIURL\fP .RS 4 Set URL pattern for source code links. The default value is extracted from git remotes ("origin" or first one) if available and the provider\(cqs URL pattern is recognized. .sp Supported replacement tags: .sp \fB%{refname}\fP .RS 4 commit reference .RE .sp \fB%{path}\fP .RS 4 path to source file inside the repository .RE .sp \fB%{filename}\fP .RS 4 basename of the source file .RE .sp \fB%{line}\fP .RS 4 line number .RE .sp If this option is missing and can\(cqt be automatically determined, the generator can\(cqt produce source code links. .RE .sp \fB\-o\fP \fIDIR\fP, \fB\-\-output\fP \fIDIR\fP .RS 4 Set the output directory (default: ./docs). .RE .sp \fB\-b\fP \fIURL\fP, \fB\-\-canonical\-base\-url\fP \fIURL\fP .RS 4 Indicate the preferred URL with rel="canonical" link element. .RE .sp \fB\-b\fP \fIURL\fP, \fB\-\-sitemap\-base\-url\fP \fIURL\fP .RS 4 Set the sitemap base URL. Sitemap will only be generated when this option is set. .RE .sp \fB\-\-sitemap\-priority\fP \fIPRIO\fP .RS 4 Set the priority assigned to sitemap entries (default: 1.0). .RE .sp \fB\-\-sitemap\-changefreq\fP \fIFREQ\fP .RS 4 Set the changefreq assigned to sitemap entries (default: never). .RE .SS "env" .sp \fBenv\fP [variables] .sp Print Crystal\-specific environment variables in a format compatible with shell scripts. If one or more variable names are given as arguments, it prints only the value of each named variable on its own line. .sp Variables: .sp \fBCRYSTAL_CACHE_DIR\fP .RS 4 Please see ENVIRONMENT VARIABLES. .RE .sp \fBCRYSTAL_EXEC_PATH\fP .RS 4 Please see ENVIRONMENT VARIABLES. .RE .sp \fBCRYSTAL_LIBRARY_PATH\fP .RS 4 Please see ENVIRONMENT VARIABLES. .RE .sp \fBCRYSTAL_PATH\fP .RS 4 Please see ENVIRONMENT VARIABLES. .RE .sp \fBCRYSTAL_VERSION\fP .RS 4 Contains Crystal version. .RE .SS "eval" .sp \fBeval\fP [options] [source] .sp Evaluate code from arguments or, if no arguments are passed, from the standard input. Useful for experiments. .sp Options: .sp \fB\-d\fP, \fB\-\-debug\fP .RS 4 Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. .RE .sp \fB\-\-no\-debug\fP .RS 4 Generate the output without any symbolic debug symbols. .RE .sp \fB\-D\fP \fIFLAG\fP, \fB\-\-define\fP \fIFLAG\fP .RS 4 Define a compile\-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with \-\-target\-triple or the hosts default, if none is given. .RE .sp \fB\-\-error\-trace\fP .RS 4 Show full error trace. .RE .sp \fB\-O\fP \fILEVEL\fP .RS 4 Optimization mode: 0 (default), 1, 2, 3. See \fBOPTIMIZATIONS\fP for details. .RE .sp \fB\-\-release\fP .RS 4 Compile in release mode. Equivalent to \fB\-O3 \-\-single\-module\fP .RE .sp \fB\-s\fP, \fB\-\-stats\fP .RS 4 Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. .RE .sp \fB\-p\fP, \fB\-\-progress\fP .RS 4 Print statistics about the progress for the current build. .RE .sp \fB\-t\fP, \fB\-\-time\fP .RS 4 Print statistics about the execution time. .RE .sp \fB\-\-no\-color\fP .RS 4 Disable colored output. .RE .SS "play" .sp \fBplay\fP [options] [file] .sp Starts the \fBcrystal\fP playground server on port 8080, by default. .sp Options: .sp \fB\-p\fP \fIPORT\fP, \fB\-\-port\fP \fIPORT\fP .RS 4 Run the playground on the specified port. Default is 8080. .RE .sp \fB\-b\fP \fIHOST\fP, \fB\-\-binding\fP \fIHOST\fP .RS 4 Bind the playground to the specified IP. .RE .sp \fB\-v\fP, \fB\-\-verbose\fP .RS 4 Display detailed information of the executed code. .RE .SS "run" .sp \fBrun\fP [options] [programfile] [\-\-] [arguments] .sp The default command. Compile and run program. .sp Options: Same as the build options. .SS "spec" .sp spec [options] [files] .sp Compile and run specs (in spec directory). .sp Options: .sp \fB\-d\fP, \fB\-\-debug\fP .RS 4 Generate the output with symbolic debug symbols. These are read when debugging the built program with tools like lldb, gdb, valgrind etc. and provide mappings to the original source code for those tools. .RE .sp \fB\-\-no\-debug\fP .RS 4 Generate the output without any symbolic debug symbols. .RE .sp \fB\-D\fP \fIFLAG\fP, \fB\-\-define\fP \fIFLAG\fP .RS 4 Define a compile\-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with \fB\-\-target\-triple\fP or the hosts default, if none is given. .RE .sp \fB\-\-error\-trace\fP .RS 4 Show full error trace. .RE .sp \fB\-O\fP \fILEVEL\fP .RS 4 Optimization mode: 0 (default), 1, 2, 3. See \fBOPTIMIZATIONS\fP for details. .RE .sp \fB\-\-release\fP .RS 4 Compile in release mode. Equivalent to \fB\-O3 \-\-single\-module\fP .RE .sp \fB\-s\fP, \fB\-\-stats\fP .RS 4 Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process. .RE .sp \fB\-p\fP, \fB\-\-progress\fP .RS 4 Print statistics about the progress for the current build. .RE .sp \fB\-t\fP, \fB\-\-time\fP .RS 4 Print statistics about the execution time. .RE .sp \fB\-\-no\-color\fP .RS 4 Disable colored output. .RE .SS "tool" .sp \fBtool\fP [tool] [switches] [programfile] [\-\-] [arguments] .sp Run a tool. The available tools are: context, dependencies, expand, flags, format, hierarchy, implementations, types, and unreachable. .sp Tools: .sp \fBcontext\fP .RS 4 Show context for given location. .RE .sp \fBdependencies\fP .RS 4 Show tree of required source files. .sp Options: .sp \fB\-D\fP \fIFLAG\fP, \fB\-\-define\fP=\fIFLAG\fP .RS 4 Define a compile\-time flag. This is useful to con ditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with \fB\-\-tar\fP get\-triple or the hosts default, if none is given. .RE .sp \fB\-f\fP \fIFORMAT\fP, \fB\-\-format\fP=\fIFORMAT\fP .RS 4 Output format \*(Aqtree\*(Aq (default), \*(Aqflat\*(Aq, \*(Aqdot\*(Aq, or \*(Aqmermaid\*(Aq. .RE .sp \fB\-i\fP \fIPATH\fP, \fB\-\-include\fP=\fIPATH\fP .RS 4 Include path in output. .RE .sp \fB\-e\fP \fIPATH\fP, \fB\-\-exclude\fP=\fIPATH\fP .RS 4 Exclude path in output. .RE .sp \fB\-\-error\-trace\fP .RS 4 Show full error trace. .RE .sp \fB\-\-prelude\fP .RS 4 Specify prelude to use. The default one initializes the garbage collector. You can also use \fB\-\-pre\fP lude=empty to use no preludes. This can be useful for checking code generation for a specific source code file. .RE .sp \fB\-\-verbose\fP .RS 4 Show skipped and heads of filtered paths .RE .RE .sp \fBexpand\fP .RS 4 Show macro expansion for given location. .RE .sp \fBflags\fP .RS 4 Print all macro \*(Aqflag?\*(Aq values .RE .sp \fBformat\fP .RS 4 Format project, directories and/or files with the coding style used in the standard library. You can use the \fB\-\-checkflag\fP to check whether the formatter would make any changes. .RE .sp \fBhierarchy\fP .RS 4 Show hierarchy of types from file. Also show class and struct members, with type and size. Types can be filtered with a regex by using the \fB\-e\fP flag. .RE .sp \fBimplementations\fP .RS 4 Show implementations for a given call. Use \fB\-\-cursor\fP to specify the cursor position. The format for the cursor position is file:line:column. .RE .sp \fBtypes\fP .RS 4 Show type of main variables of file. .RE .sp \fBunreachable\fP .RS 4 Show methods that are never called. The text output is a list of lines with columns separated by tab. .sp Output fields: .sp \fBcount\fP .RS 4 sum of all calls to this method (only with \fB\-\-tallies\fP option; otherwise skipped) .RE .sp \fBlocation\fP .RS 4 pathname, line and column, all separated by colon name .RE .sp \fBlines\fP .RS 4 length of the def in lines annotations .RE .sp Options: .sp \fB\-D\fP \fIFLAG\fP, \fB\-\-define\fP=\fIFLAG\fP .RS 4 Define a compile\-time flag. This is useful to con ditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with \fB\-\-target\-triple\fP or the hosts default, if none is given. .RE .sp \fB\-f\fP \fIFORMAT\fP, \fB\-\-format\fP=\fIFORMAT\fP .RS 4 Output format \*(Aqtext\*(Aq (default), \*(Aqjson\*(Aq, \*(Aqcodecov\*(Aq, or \*(Aqcsv\*(Aq. .RE .sp \fB\-\-tallies\fP .RS 4 Print reachable methods and their call counts as well. .RE .sp \fB\-\-check\fP .RS 4 Exit with error if there is any unreachable code. .RE .sp \fB\-i\fP \fIPATH\fP, \fB\-\-include\fP=\fIPATH\fP .RS 4 Include path in output. .RE .sp \fB\-e\fP \fIPATH\fP, \fB\-\-exclude\fP=\fIPATH\fP .RS 4 Exclude path in output (default: lib). .RE .sp \fB\-\-error\-trace\fP .RS 4 Show full error trace. .RE .sp \fB\-\-prelude\fP .RS 4 Specify prelude to use. The default one initializes the garbage collector. You can also use \fB\-\-prelude=empty\fP to use no preludes. This can be useful for checking code generation for a specific source code file. .RE .RE .SS "clear_cache" .sp Clear the compiler cache (located at \*(AqCRYSTAL_CACHE_DIR\*(Aq). .SS "help" .sp Show help. Option \fB\-\-help\fP or \fB\-h\fP can also be added to each command for command\-specific help. .SS "version" .sp Show version. .SH "OPTIMIZATIONS" .sp The optimization level specifies the codegen effort for producing optimal code. It\(cqs a trade\-off between compilation performance (decreasing per optimization level) and runtime performance (increasing per optimization level). .sp Production builds should usually have the highest optimization level. Best results are achieved with \fB\-\-release\fP which also implies \fB\-\-single\-module\fP .sp \fB\-O0\fP .RS 4 No optimization (default) .RE .sp \fB\-O1\fP .RS 4 Low optimization .RE .sp \fB\-O2\fP .RS 4 Middle optimization .RE .sp \fB\-O3\fP .RS 4 High optimization .RE .sp \fB\-Os\fP .RS 4 Middle optimization with focus on file size .RE .sp \fB\-Oz\fP .RS 4 Middle optimization aggressively focused on file size .RE .SH "ENVIRONMENT VARIABLES" .SS "CRYSTAL_CACHE_DIR" .sp Defines path where Crystal caches partial compilation results for faster subsequent builds. This path is also used to temporarily store executables when Crystal programs are run with \*(Aq\fBcrystal\fP run\*(Aq rather than \*(Aq\fBcrystal\fP build\*(Aq. .SS "CRYSTAL_EXEC_PATH" .sp Determines the path where crystal looks for external sub-commands. .SS "CRYSTAL_LIBRARY_PATH" .sp Defines paths where Crystal searches for (binary) libraries. Multiple paths can be separated by ":". These paths are passed to the linker as \f(CR\-L\fP flags. .sp The pattern \*(Aq$ORIGIN\*(Aq at the start of the path expands to the directory where the compiler binary is located. For example, \*(Aq$ORIGIN/../lib/crystal\*(Aq resolves the standard library path relative to the compiler location in a generic way, independent of the absolute paths (assuming the relative location is correct). .SS "CRYSTAL_PATH" .sp Defines paths where Crystal searches for required source files. Multiple paths can be separated by ":". .sp The pattern \*(Aq$ORIGIN\*(Aq at the start of the path expands to the directory where the compiler binary is located. For example, \*(Aq$ORIGIN/../share/crystal/src\*(Aq resolves the standard library path relative to the compiler location in a generic way, independent of the absolute paths (assuming the relative location is correct). .SS "CRYSTAL_OPTS" .sp Defines options for the Crystal compiler to be used besides the command line arguments. The syntax is identical to the command line arguments. This is handy when using Crystal in build setups, for example \*(AqCRYSTAL_OPTS=\-\-debug make build\*(Aq. .SH "SEEALSO" .sp \fBshards\fP(1) .sp .URL "https://crystal\-lang.org/" "" "" The official web site. .sp .URL "https://github.com/crystal\-lang/crystal" "" "" Official Repository. ================================================ FILE: samples/2048.cr ================================================ # Based on 2048 by Gabriele Cirulli - gabrielecirulli.github.io/2048 require "colorize" enum Action Up Down Left Right Escape Unknown end module Screen TILES = { 0 => {Colorize::ColorANSI::White, nil}, 2 => {Colorize::ColorANSI::Black, Colorize::ColorANSI::White}, 4 => {Colorize::ColorANSI::Blue, Colorize::ColorANSI::White}, 8 => {Colorize::ColorANSI::Black, Colorize::ColorANSI::Yellow}, 16 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Red}, 32 => {Colorize::ColorANSI::Black, Colorize::ColorANSI::Red}, 64 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Magenta}, 128 => {Colorize::ColorANSI::Red, Colorize::ColorANSI::Yellow}, 256 => {Colorize::ColorANSI::Magenta, Colorize::ColorANSI::Yellow}, 512 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Yellow}, 1024 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Yellow}, 2048 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Yellow}, 4096 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Black}, 8192 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Black}, 16384 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Black}, 32768 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Black}, 65536 => {Colorize::ColorANSI::White, Colorize::ColorANSI::Black}, } def self.colorize_for(tile, &) fg_color, bg_color = TILES[tile] color = Colorize.with.fore(fg_color) color = color.back(bg_color) if bg_color color.surround do yield end end def self.clear print "\e[2J\e[1;1H" end def self.read_keypress STDIN.raw do |io| buffer = Bytes.new(3) bytes_read = io.read(buffer) return Action::Unknown if bytes_read == 0 input = String.new(buffer[0, bytes_read]) case input when "\e[A", "w" Action::Up when "\e[B", "s" Action::Down when "\e[C", "d" Action::Right when "\e[D", "a" Action::Left when "\e", "\u{3}", "q", "Q" Action::Escape else Action::Unknown end end end end class Drawer INNER_CELL_WIDTH = 16 INNER_CELL_HEIGHT = 6 def initialize @n = 0 @grid = [] of Array(String) @current_row = [] of String @content_line = false end def set_current_row(row) @current_row = row end def draw(grid) @grid = grid @n = @grid.size Screen.clear box end def box top_border (@n - 1).times do |row| tile row mid_border end tile @n - 1 bottom_border end def tile(row) set_current_row @grid[row] INNER_CELL_HEIGHT.times do |i| if i == (@n / 2) + 1 content_line else space_line end end set_current_row [] of String end def space_line line '│', " ", '│', '│' end def content_line @content_line = true space_line @content_line = false end def top_border line '┌', "─", '┬', '┐' end def mid_border line '├', "─", '┼', '┤' end def bottom_border line '└', "─", '┴', '┘' end def line(left, fill, inner, right) print left (@n - 1).times do |cell| cell_line fill, cell print inner end cell_line fill, @n - 1 puts right end def cell_line(fill, cell) content = @current_row.fetch(cell) { "empty" } tile_value = (content == "empty" ? 0 : (content.to_i? || 0)).to_i content = "" if !@content_line || content == "empty" fill_size = INNER_CELL_WIDTH // 2 fill_size -= content.size // 2 fill_size -= 2 print fill Screen.colorize_for(tile_value) do print fill*fill_size print content print fill*fill_size print fill if content.size % 2 == 0 end print fill end end class Game def initialize @drawer = Drawer.new @grid = [ [nil, nil, nil, nil] of Int32?, [nil, nil, nil, nil] of Int32?, [nil, nil, nil, nil] of Int32?, [nil, nil, nil, nil] of Int32?, ] insert_tile insert_tile end def run draw until won? || lost? if execute_action read_action insert_tile draw end end if won? end_game "You won!" elsif lost? end_game "You lost!" else raise "Game loop quit unexpectedly" end end def draw @drawer.draw drawable_grid end def drawable_grid @grid.map &.map(&.to_s) end def read_action Screen.read_keypress end def insert_tile value = rand > 0.8 ? 4 : 2 empty_cells = @grid.sum(&.count &.nil?) fill_cell = empty_cells > 1 ? rand(empty_cells - 1) + 1 : 1 empty_cell_count = 0 each_cell_with_index do |tile, row, col| empty_cell_count += 1 unless tile if empty_cell_count == fill_cell @grid[row][col] = value return end end end def each_cell_with_index(&) 0.upto(@grid.size - 1) do |row| 0.upto(@grid.size - 1) do |col| yield @grid[row][col], row, col end end end def execute_action(action) case action in .up?, .down?, .left?, .right? if can_move_in? action shift_grid action true else false end in .escape? end_game "Bye" in .unknown? false # ignore end end def shift_grid(direction) drow, dcol = offsets_for direction shift_tiles_to_empty_cells direction, drow, dcol merge_tiles direction, drow, dcol shift_tiles_to_empty_cells direction, drow, dcol end def shift_tiles_to_empty_cells(direction, drow, dcol) modified = true while modified modified = false movable_tiles(direction, drow, dcol) do |tile, row, col| unless @grid[row + drow][col + dcol] @grid[row + drow][col + dcol] = tile @grid[row][col] = nil modified = true end end end end def merge_tiles(direction, drow, dcol) movable_tiles(direction, drow, dcol) do |tile, row, col| if @grid[row + drow][col + dcol] == tile @grid[row][col] = nil @grid[row + drow][col + dcol] = tile*2 end end end def movable_tiles(direction, drow, dcol, &) max = @grid.size - 1 from_row, to_row, from_column, to_column = case direction when .up?, .left? {0, max, 0, max} when .down?, .right? {max, 0, max, 0} else raise ArgumentError.new "Unknown direction #{direction}" end from_row.to(to_row) do |row| from_column.to(to_column) do |col| tile = @grid[row][col] if tile && !to_border?(direction, row, col, drow, dcol) yield tile, row, col end end end end def can_move_in?(direction) drow, dcol = offsets_for direction movable_tiles(direction, drow, dcol) do |tile, row, col| target_tile = @grid[row + drow][col + dcol] return true if !target_tile || target_tile == tile end false end def offsets_for(direction) drow = dcol = 0 case direction when .up? drow = -1 when .down? drow = 1 when .left? dcol = -1 when .right? dcol = 1 else raise ArgumentError.new "Unknown direction #{direction}" end {drow, dcol} end def to_border?(direction, row, col, drow, dcol) case direction when .up? row + drow < 0 when .down? row + drow >= @grid.size when .left? col + dcol < 0 when .right? col + dcol >= @grid.size else false end end def won? @grid.any? &.any?(&.==(2048)) end def lost? !can_move? end def can_move? can_move_in?(Action::Up) || can_move_in?(Action::Down) || can_move_in?(Action::Left) || can_move_in?(Action::Right) end def end_game(msg) puts msg exit end end at_exit { STDIN.cooked! } Game.new.run ================================================ FILE: samples/Makefile ================================================ CRYSTAL := ../bin/crystal## Crystal compiler to use O := .build## Output directory BUILDABLE_SOURCES := $(wildcard *.cr llvm/*.cr compiler/*.cr) NONLINK_SOURCES := $(wildcard sdl/*.cr) BUILDABLE_BINARIES := $(patsubst %.cr,$(O)/%,$(BUILDABLE_SOURCES)) NONLINK_BINARIES := $(patsubst %.cr,$(O)/%.o,$(NONLINK_SOURCES)) .PHONY: all all: build .PHONY: build build: $(BUILDABLE_BINARIES) $(NONLINK_BINARIES) ## Build sample binaries $(O)/%: %.cr mkdir -p $(shell dirname $@) $(CRYSTAL) build $< -o $@ $(O)/%.o: %.cr mkdir -p $(shell dirname $@) $(CRYSTAL) build --cross-compile $< -o $(patsubst %.o,%,$@) .PHONY: clean clean: ## Remove build artifacts rm -rf $(O) .PHONY: help help: ## Show this help @echo @printf '\033[34mtargets:\033[0m\n' @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34moptional variables:\033[0m\n' @grep -hE '^[a-zA-Z_-]+ \?=.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = " \\?=.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34mrecipes:\033[0m\n' @grep -hE '^##.*$$' $(MAKEFILE_LIST) |\ awk 'BEGIN {FS = "## "}; /^## [a-zA-Z_-]/ {printf " \033[36m%s\033[0m\n", $$2}; /^## / {printf " %s\n", $$2}' ================================================ FILE: samples/Makefile.win ================================================ all: MAKEFLAGS += --no-builtin-rules .SUFFIXES: SHELL := cmd.exe MKDIR = if not exist $1 mkdir $1 RMDIR = if exist $1 rd /S /Q $1 CRYSTAL := ..\bin\crystal.bat# Crystal compiler to use O := .build# Output directory BUILDABLE_SOURCES := $(wildcard *.cr llvm/*.cr compiler/*.cr) NONLINK_SOURCES := $(wildcard sdl/*.cr) BUILDABLE_BINARIES := $(patsubst %.cr,$(O)/%.exe,$(BUILDABLE_SOURCES)) NONLINK_BINARIES := $(patsubst %.cr,$(O)/%.obj,$(NONLINK_SOURCES)) .PHONY: all all: build .PHONY: build build: $(BUILDABLE_BINARIES) $(NONLINK_BINARIES) ## Build sample binaries $(O)/%.exe: %.cr $(call MKDIR,"$(dir $@)") $(CRYSTAL) build "$<" -o "$@" $(O)/%.obj: %.cr $(call MKDIR,"$(dir $@)") $(CRYSTAL) build --cross-compile "$<" -o "$(patsubst %.obj,%,$@)" .PHONY: clean clean: ## Remove build artifacts $(call RMDIR,"$(O)") .PHONY: help help: ## Show this help @setlocal EnableDelayedExpansion &\ echo. &\ echo targets: &\ (for /F "usebackq tokens=1* delims=:" %%g in ($(MAKEFILE_LIST)) do (\ if not "%%h" == "" (\ set "_line=%%g " &\ set "_rest=%%h" &\ set "_comment=!_rest:* ## =!" &\ if not "!_comment!" == "!_rest!"\ if "!_line:_rest=!" == "!_line!"\ echo !_line:~0,16!!_comment!\ )\ )) &\ echo. &\ echo optional variables: &\ (for /F "usebackq tokens=1,3 delims=?#" %%g in ($(MAKEFILE_LIST)) do (\ if not "%%h" == "" (\ set "_var=%%g " &\ echo !_var:~0,14! %%h\ )\ )) &\ echo. &\ echo recipes: &\ (for /F "usebackq tokens=* delims=" %%g in ($(MAKEFILE_LIST)) do (\ set "_line=%%g" &\ if "!_line:~0,7!" == "## $$ " (\ echo !_name! &\ echo !_line:~2!\ ) else if "!_line:~0,3!" == "## "\ set "_name= !_line:~3!"\ )) ================================================ FILE: samples/binary-trees.cr ================================================ # Copied with little modifications from: https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/binarytrees-yarv-1.html class Node def initialize(@a : Node?, @b : Int32, @c : Node?) end property :a property :b property :c end def item_check(tree) tree = tree.not_nil! return tree.b if tree.a.nil? tree.b + item_check(tree.a) - item_check(tree.c) end def bottom_up_tree(item, depth) return Node.new(nil, item, nil) unless depth > 0 item_item = 2 * item depth -= 1 Node.new(bottom_up_tree(item_item - 1, depth), item, bottom_up_tree(item_item, depth)) end max_depth = (ARGV[0]? || 15).to_i min_depth = 4 max_depth = min_depth + 2 if min_depth + 2 > max_depth stretch_depth = max_depth + 1 stretch_tree = bottom_up_tree(0, stretch_depth) puts "stretch tree of depth #{stretch_depth}\t check: #{item_check(stretch_tree)}" long_lived_tree = bottom_up_tree(0, max_depth) min_depth.step(to: max_depth + 1, by: 2) do |depth| iterations = 2**(max_depth - depth + min_depth) check = 0 (1..iterations).each do |i| temp_tree = bottom_up_tree(i, depth) check += item_check(temp_tree) temp_tree = bottom_up_tree(-i, depth) check += item_check(temp_tree) end puts "#{iterations * 2}\t trees of depth #{depth}\t check: #{check}" end puts "long lived tree of depth #{max_depth}\t check: #{item_check(long_lived_tree)}" ================================================ FILE: samples/brainfuck.cr ================================================ # Brainf*ck interpreter struct Tape def initialize @tape = [0] @pos = 0 end def get @tape[@pos] end def inc @tape[@pos] += 1 end def dec @tape[@pos] -= 1 end def advance @pos += 1 @tape << 0 if @tape.size <= @pos end def devance @pos -= 1 raise "pos should be > 0" if @pos < 0 end def set(value) @tape[@pos] = value end end class Program def initialize(@chars : Array(Char), @bracket_map : Hash(Int32, Int32)) end def run tape = Tape.new pc = 0 while pc < @chars.size case @chars[pc] when '>'; tape.advance when '<'; tape.devance when '+'; tape.inc when '-'; tape.dec when '.'; print tape.get.chr when ','; STDIN.read_byte.try { |byte| tape.set byte.to_i } when '['; pc = @bracket_map[pc] if tape.get == 0 when ']'; pc = @bracket_map[pc] if tape.get != 0 else # skip end pc += 1 end end def self.parse(text) parsed = [] of Char bracket_map = {} of Int32 => Int32 leftstack = [] of Int32 pc = 0 text.each_char do |char| if "[]<>+-,.".includes?(char) parsed << char if char == '[' leftstack << pc elsif char == ']' && !leftstack.empty? left = leftstack.pop right = pc bracket_map[left] = right bracket_map[right] = left end pc += 1 end end Program.new(parsed, bracket_map) end end text = if ARGV.size > 0 File.read(ARGV[0]) else <<-PROGRAM Benchmark brainf*ck program >++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++ [>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++ ++++++++[>++++++++++[>++++++++++[>++++++++++[>+ +++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++. PROGRAM end Program.parse(text).run ================================================ FILE: samples/channel_primes.cr ================================================ # Ported from Go sample from this page: https://web.archive.org/web/20160602135806/http://dancallahan.info/journal/go-concurrency/#How+do+channels+and+goroutines+work+together? def generate(chan) i = 2 loop do chan.send(i) i += 1 end end def filter(in_chan, out_chan, prime) loop do i = in_chan.receive if i % prime != 0 out_chan.send(i) end end end ch = Channel(Int32).new spawn generate(ch) 100.times do prime = ch.receive puts prime ch1 = Channel(Int32).new spawn filter(ch, ch1, prime) ch = ch1 end ================================================ FILE: samples/channel_select.cr ================================================ def generator(n : T) forall T channel = Channel(T).new spawn do loop do sleep n.seconds channel.send n end end channel end ch1 = generator(1) ch2 = generator(1.5) ch3 = generator(5) loop do select when int = ch1.receive puts "Int: #{int}" when float = ch2.receive puts "Float: #{float}" when ch3.receive break end end ================================================ FILE: samples/compiler/formatter_example.cr ================================================ # This is a small sample on how to use a Crystal's # formatter programmatically. # Use `require "compiler/crystal/formatter"` in your programs require "../../src/compiler/crystal/formatter" source = "[ 1 , 2 , 3].map { | x | x.to_s }" result = Crystal.format(source) puts result ================================================ FILE: samples/compiler/transformer_example.cr ================================================ # This is a small sample on how to use a Crystal::Transformer # to transform source code. # # Here we transform all number literals with their char # equivalent using `chr`. # Use `require "compiler/crystal/syntax"` in your programs require "../../src/compiler/crystal/syntax" class Charify < Crystal::Transformer def transform(node : Crystal::NumberLiteral) Crystal::CharLiteral.new(node.value.to_i.chr) end end nodes = Crystal::Parser.parse("hello(99, 114, 121, 115, 116, 97, 108)") puts nodes.transform(Charify.new) ================================================ FILE: samples/compiler/visitor_example.cr ================================================ # This is a small sample on how to use a Crystal::Visitor # to traverse an AST. # # Here we count the number of NumberLiterals in a program. # Use `require "compiler/crystal/syntax"` in your programs require "../../src/compiler/crystal/syntax" class Counter < Crystal::Visitor getter count def initialize @count = 0 end def visit(node : Crystal::NumberLiteral) @count += 1 false end def visit(node : Crystal::ASTNode) # true: we want to the visitor to visit node's children true end end nodes = Crystal::Parser.parse("hello(99, 114, 121, 115, 116, 97, 108)") counter = Counter.new nodes.accept counter puts counter.count ================================================ FILE: samples/conway.cr ================================================ # Ported from http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html struct ANSI def initialize(@io : IO) end def clear @io << "\e[2J" end def pos(x, y) @io << "\e[" << x << ';' << y << 'H' end end class IO def ansi ANSI.new self end end struct ConwayMap WIDTH = 40 HEIGHT = 30 include Math @map : Array(Array(Bool)) def initialize(pattern) @map = Array.new(HEIGHT) { Array.new(WIDTH, false) } ix = min WIDTH, pattern.max_of(&.size) iy = min HEIGHT, pattern.size dx = (WIDTH - ix) // 2 dy = (HEIGHT - iy) // 2 iy.times do |y| ix.times do |x| if x < pattern[y].size && !pattern[y][x].whitespace? @map[y + dy][x + dx] = true end end end end def next old_map = @map.clone HEIGHT.times do |i| WIDTH.times do |j| nlive = 0 max(i - 1, 0).upto(min(i + 1, HEIGHT - 1)) do |i2| max(j - 1, 0).upto(min(j + 1, WIDTH - 1)) do |j2| nlive += 1 if old_map[i2][j2] && (i2 != i || j2 != j) end end if @map[i][j] @map[i][j] = 2 <= nlive <= 3 else @map[i][j] = nlive == 3 end end end end def to_s(io) io.ansi.clear io.ansi.pos 1, 1 @map.each do |row| row.each do |cell| io << (cell ? "()" : ". ") end io.puts end end end PAUSE = 20.milliseconds DEFAULT_COUNT = 300 INITIAL_MAP = [ " 1 ", " 1 1 ", " 11 11 11", " 1 1 11 11", "11 1 1 11 ", "11 1 1 11 1 1 ", " 1 1 1 ", " 1 1 ", " 11 ", ] map = ConwayMap.new INITIAL_MAP spawn { gets; exit } 1.upto(DEFAULT_COUNT) do |i| puts map puts "n = #{i}\tPress ENTER to exit" sleep PAUSE map.next end ================================================ FILE: samples/degree_days.cr ================================================ # Copied with little modifications from: https://github.com/rubinius/rubinius-benchmark/blob/master/real_world/bench_degree_days.rb class DegreeDays def initialize(@daily_temperatures : Array(Array(Int32)), @options = {} of String => Float64) end property :daily_temperatures def calculate heating = 0.0 cooling = 0.0 heating_days = 0.0 cooling_days = 0.0 daily_temperatures.each do |day| heating_today = heating_day(day) cooling_today = cooling_day(day) if heating_today heating_days += 1 heating += heating_today end if cooling_today cooling_days += 1 cooling += cooling_today end end { "heating" => heating, "cooling" => cooling, "heating_days" => heating_days, "cooling_days" => cooling_days, } end private def sum(ary) ary.reduce(0) { |a, i| a + i } end private def avg(ary) sum(ary).to_f / ary.size.to_f end private def heating_day(temps) heat = avg temps.map { |temp| heating_degree(temp) } (heat > heating_threshold) ? heat : nil end private def cooling_day(temps) cool = avg temps.map { |temp| cooling_degree(temp) } (cool > cooling_threshold) ? cool : nil end private def heating_degree(temp) deg = base_temperature - (temp + heating_insulation) {deg, 0}.max end private def cooling_degree(temp) deg = (temp - cooling_insulation) - base_temperature {deg, 0}.max end private def base_temperature @options["base_temperature"]? || 65.0 end private def heating_insulation @options["heating_insulation"]? || insulation_factor || 3 end private def cooling_insulation @options["cooling_insulation"]? || insulation_factor || 0 end private def insulation_factor @options["insulation_factor"]? end private def heating_threshold @options["heating_threshold"]? || threshold || 6 end private def cooling_threshold @options["cooling_threshold"]? || threshold || 3 end private def threshold @options["threshold"]? end end (ARGV[0]? || 300).to_i.times do |i| days_in_year = 365 hours_in_day = 24 hot_day = Array.new(hours_in_day, 92) cold_day = Array.new(hours_in_day, 37) # 182 hot days + 183 cold days temperatures = Array.new((days_in_year / 2.0).floor.to_i, hot_day) + Array.new((days_in_year / 2.0).ceil.to_i, cold_day) degree_days = DegreeDays.new(temperatures) res = degree_days.calculate p res if i == 0 end ================================================ FILE: samples/egrep.cr ================================================ if ARGV.empty? abort "Usage: cat somefile | egrep 'some'" end regex = Regex.new(ARGV[0]) while str = STDIN.gets STDOUT.print(str) if str =~ regex end ================================================ FILE: samples/fannkuch-redux.cr ================================================ # Copied with little modifications from: https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/fannkuchredux-yarv-1.html def fannkuch(n) sign, maxflips, sum = 1, 0, 0 w = [0].concat((1..n).to_a) q = w.dup s = w.dup while true # Copy and flip. q1 = w[1] # Cache 1st element. if q1 != 1 q = w.dup flips = 1 while true qq = q[q1] if qq == 1 # ... until 1st element is 1. sum = sum + sign * flips maxflips = flips if flips > maxflips # New maximum? break end q[q1] = q1 if q1 >= 4 i, j = 2, q1 - 1 while true q.swap i, j i = i + 1 j = j - 1 break if !(i < j) end end q1 = qq flips = flips + 1 end end # Permute. if sign == 1 # Rotate 1<-2. w.swap 1, 2 sign = -1 else # Rotate 1<-2 and 1<-2<-3. w.swap 2, 3 sign = 1 3.upto(n) do |ki| unless s[ki] == 1 s[ki] = s[ki] - 1 break end return [sum, maxflips] if ki == n # Out of permutations. s[ki] = ki # Rotate 1<-...<-i+1. t = w[1] 1.upto(ki) do |kj| w[kj] = w[kj + 1] end w[ki + 1] = t end end end end n = (ARGV[0]? || 10).to_i sum, flips = fannkuch(n) puts "#{sum}\nPfannkuchen(#{n}) = #{flips}" ================================================ FILE: samples/fibonacci.cr ================================================ def fibonacci(n : Int32) : Int32 return 0 if n < 0 return n if n <= 1 fibonacci(n - 1) + fibonacci(n - 2) end puts "First ten Fibonacci numbers:" (0..9).each do |n| puts "fibonacci(#{n}) = #{fibonacci(n)}" end ================================================ FILE: samples/havlak.cr ================================================ # Havlak benchmark: https://code.google.com/p/multi-language-bench/ # Crystal Implementation (translated from Python version) # Intel i5 2.5GHz # crystal: 26.5s 359Mb # c++: 28.2s 150Mb # java: 31.5s 909Mb # scala: 66.8s 316Mb # go: 67.7s 456Mb # python: 958.4s 713Mb class BasicBlock def initialize(@name : Int32) @in_edges = [] of BasicBlock @out_edges = [] of BasicBlock end property :in_edges property :out_edges def to_s(io) io << "BB#" io << @name end end struct BasicBlockEdge @from : BasicBlock @to : BasicBlock def initialize(cfg, from_name, to_name) @from = cfg.create_node(from_name) @to = cfg.create_node(to_name) @from.out_edges << @to @to.in_edges << @from end def self.add(cfg, from_name, to_name) edge = new(cfg, from_name, to_name) cfg.add_edge(edge) end end class CFG def initialize @basic_block_map = {} of Int32 => BasicBlock @edge_list = [] of BasicBlockEdge end property start_node : BasicBlock? property :basic_block_map def create_node(name) node = @basic_block_map.put_if_absent(name) { BasicBlock.new(name) } @start_node ||= node node end def add_edge(edge) @edge_list << edge end def num_nodes @basic_block_map.size end end class SimpleLoop def initialize @basic_blocks = Set(BasicBlock).new @children = Set(SimpleLoop).new @parent = nil @header = nil @root = false @reducible = true @counter = 0 @nesting_level = 0 @depth_level = 0 end property :counter property? :reducible property? :root getter :parent property :depth_level property :children getter :nesting_level def add_node(bb) @basic_blocks.add(bb) end def add_child_loop(l) @children.add(l) end def parent=(parent : SimpleLoop) @parent = parent parent.add_child_loop(self) end def header=(bb : BasicBlock) @basic_blocks.add(bb) @header = bb end def nesting_level=(level) @nesting_level = level @root = true if level == 0 end end class LSG @@loop_counter = 0 @root : SimpleLoop def initialize @loops = [] of SimpleLoop @root = create_new_loop @root.nesting_level = 0 add_loop(@root) end def create_new_loop s = SimpleLoop.new s.counter = @@loop_counter += 1 s end def add_loop(l) @loops << l end def calculate_nesting_level @loops.each do |liter| liter.parent = @root if !liter.root? && liter.parent == nil end calculate_nesting_level_rec(@root, 0) end def calculate_nesting_level_rec(l, depth) l.depth_level = depth l.children.each do |liter| calculate_nesting_level_rec(liter, depth + 1) l.nesting_level = Math.max(l.nesting_level, 1 + liter.nesting_level) end end def num_loops @loops.size end end class UnionFindNode def initialize @parent = nil @bb = nil @l = nil @dfs_number = 0 end def init_node(bb, dfs_number) @parent = self @bb = bb @dfs_number = dfs_number end property bb : BasicBlock? property parent : self? property dfs_number : Int32 property l : SimpleLoop? def find_set node_list = [] of UnionFindNode node = self while node != node.parent parent = node.parent.not_nil! node_list << node if parent != parent.parent node = parent end node_list.each { |iter| iter.parent = node.parent } node end def union(union_find_node) @parent = union_find_node end end class HavlakLoopFinder BB_TOP = 0 # uninitialized BB_NONHEADER = 1 # a regular BB BB_REDUCIBLE = 2 # reducible loop BB_SELF = 3 # single BB loop BB_IRREDUCIBLE = 4 # irreducible loop BB_DEAD = 5 # a dead BB BB_LAST = 6 # Sentinel # Marker for uninitialized nodes. UNVISITED = -1 # Safeguard against pathologic algorithm behavior. MAXNONBACKPREDS = (32 * 1024) def initialize(@cfg : CFG, @lsg : LSG) end def ancestor?(w, v, last) w <= v <= last[w] end def dfs(current_node, nodes, number, last, current) nodes[current].init_node(current_node, current) number[current_node] = current lastid = current current_node.out_edges.each do |target| if number[target] == UNVISITED lastid = dfs(target, nodes, number, last, lastid + 1) end end last[number[current_node]] = lastid lastid end def find_loops start_node = @cfg.start_node return 0 unless start_node size = @cfg.num_nodes non_back_preds = Array.new(size) { Set(Int32).new } back_preds = Array.new(size) { Array(Int32).new } number = {} of BasicBlock => Int32 header = Array.new(size, 0) types = Array.new(size, 0) last = Array.new(size, 0) nodes = Array.new(size) { UnionFindNode.new } # Step a: # - initialize all nodes as unvisited. # - depth-first traversal and numbering. # - unreached BB's are marked as dead. # @cfg.basic_block_map.each_value { |v| number[v] = UNVISITED } dfs(start_node, nodes, number, last, 0) # Step b: # - iterate over all nodes. # # A backedge comes from a descendant in the DFS tree, and non-backedges # from non-descendants (following Tarjan). # # - check incoming edges 'v' and add them to either # - the list of backedges (back_preds) or # - the list of non-backedges (non_back_preds) # size.times do |w| header[w] = 0 types[w] = BB_NONHEADER node_w = nodes[w].bb if node_w node_w.in_edges.each do |node_v| v = number[node_v] if v != UNVISITED if ancestor?(w, v, last) back_preds[w] << v else non_back_preds[w].add(v) end end end else types[w] = BB_DEAD end end # Start node is root of all other loops. header[0] = 0 # Step c: # # The outer loop, unchanged from Tarjan. It does nothing except # for those nodes which are the destinations of backedges. # For a header node w, we chase backward from the sources of the # backedges adding nodes to the set P, representing the body of # the loop headed by w. # # By running through the nodes in reverse of the DFST preorder, # we ensure that inner loop headers will be processed before the # headers for surrounding loops. # (size - 1).downto(0) do |w| # this is 'P' in Havlak's paper node_pool = [] of UnionFindNode node_w = nodes[w].bb if node_w # dead BB # Step d: back_preds[w].each do |v| if v != w node_pool << nodes[v].find_set else types[w] = BB_SELF end end # Copy node_pool to work_list. # work_list = node_pool.dup types[w] = BB_REDUCIBLE if node_pool.size != 0 # work the list... # while !work_list.empty? x = work_list.shift # Step e: # # Step e represents the main difference from Tarjan's method. # Chasing upwards from the sources of a node w's backedges. If # there is a node y' that is not a descendant of w, w is marked # the header of an irreducible loop, there is another entry # into this loop that avoids w. # # The algorithm has degenerated. Break and # return in this case. # non_back_size = non_back_preds[x.dfs_number].size return 0 if non_back_size > MAXNONBACKPREDS non_back_preds[x.dfs_number].each do |iter| y = nodes[iter] ydash = y.find_set if !ancestor?(w, ydash.dfs_number, last) types[w] = BB_IRREDUCIBLE non_back_preds[w].add(ydash.dfs_number) else if ydash.dfs_number != w && !node_pool.includes?(ydash) work_list << ydash node_pool << ydash end end end end # Collapse/Unionize nodes in a SCC to a single node # For every SCC found, create a loop descriptor and link it in. # if (node_pool.size > 0) || (types[w] == BB_SELF) l = @lsg.create_new_loop l.header = node_w l.reducible = types[w] != BB_IRREDUCIBLE # At this point, one can set attributes to the loop, such as: # # the bottom node: # iter = back_preds(w).begin(); # loop bottom is: nodes(iter).node; # # the number of backedges: # back_preds(w).size() # # whether this loop is reducible: # types(w) != BB_IRREDUCIBLE # nodes[w].l = l node_pool.each do |node| # Add nodes to loop descriptor. header[node.dfs_number] = w node.union(nodes[w]) # Nested loops are not added, but linked together. if node_l = node.l node_l.parent = l else l.add_node(node.bb.not_nil!) end end @lsg.add_loop(l) end end end @lsg.num_loops end end def build_diamond(start) bb0 = start BasicBlockEdge.add(TOP_CFG, bb0, bb0 + 1) BasicBlockEdge.add(TOP_CFG, bb0, bb0 + 2) BasicBlockEdge.add(TOP_CFG, bb0 + 1, bb0 + 3) BasicBlockEdge.add(TOP_CFG, bb0 + 2, bb0 + 3) bb0 + 3 end def build_connect(_start, _end) BasicBlockEdge.add(TOP_CFG, _start, _end) end def build_straight(start, n) n.times do |i| build_connect(start + i, start + i + 1) end start + n end def build_base_loop(from) header = build_straight(from, 1) diamond1 = build_diamond(header) d11 = build_straight(diamond1, 1) diamond2 = build_diamond(d11) footer = build_straight(diamond2, 1) build_connect(diamond2, d11) build_connect(diamond1, header) build_connect(footer, from) build_straight(footer, 1) end TOP_CFG = CFG.new puts "Welcome to LoopTesterApp, Crystal edition" puts "Constructing Simple CFG..." TOP_CFG.create_node(0) # top build_base_loop(0) TOP_CFG.create_node(1) # bottom build_connect(0, 2) # execute loop recognition 15000 times to force compilation puts "15000 dummy loops" 15000.times do HavlakLoopFinder.new(TOP_CFG, LSG.new).find_loops end puts "Constructing CFG..." n = 2 10.times do |parlooptrees| TOP_CFG.create_node(n + 1) build_connect(2, n + 1) n = n + 1 100.times do |i| top = n n = build_straight(n, 1) 25.times { n = build_base_loop(n) } bottom = build_straight(n, 1) build_connect(n, top) n = bottom end build_connect(n, 1) end puts "Performing Loop Recognition\n1 Iteration" loops = HavlakLoopFinder.new(TOP_CFG, LSG.new).find_loops puts "Another 50 iterations..." sum = 0 50.times do |i| print '.' sum += HavlakLoopFinder.new(TOP_CFG, LSG.new).find_loops end puts "\nFound #{loops} loops (including artificial root node) (#{sum})\n" ================================================ FILE: samples/http_server.cr ================================================ # A very basic HTTP server require "http/server" server = HTTP::Server.new do |context| context.response.content_type = "text/plain" context.response.print "Hello world!" end address = server.bind_tcp 8080 puts "Listening on http://#{address}" server.listen ================================================ FILE: samples/impl.cr ================================================ class Foo property lorem : Int32? def foo 1 end end class Bar def foo 2 end end def bar(o) while false o.foo end end def baz(o) o.foo end puts bar(Foo.new) puts bar(Bar.new) puts baz(Foo.new) Foo.new.lorem # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:17:8 # # 2 implementations found # .../samples/impl.cr:4:3 # .../samples/impl.cr:10:3 # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:22:5 # # 1 implementation found # .../samples/impl.cr:4:3 # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:25:7 # # 1 implementation found # .../samples/impl.cr:15:1 # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:27:3 # # 1 implementation found # .../share/crystal/src/kernel.cr:369:1 # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:29:9 # # 1 implementation found # .../samples/impl.cr:2:3 # ~> macro property: expanded macro: macro_139913700784656:636:13 ================================================ FILE: samples/llvm/brainfuck.cr ================================================ # Ported from https://github.com/Wilfred/Brainfrack/blob/5a2f613f9e82bfd57be687aa6a67aca15d3d9861/llvm/compiler.cpp require "llvm" NUM_CELLS = 30000 CELL_SIZE_IN_BYTES = 1 abstract class Instruction abstract def compile(program, bb) end class Increment < Instruction def initialize(@amount : Int32) end def compile(program, bb) builder = program.builder builder.position_at_end bb cell_index = builder.load program.ctx.int32, program.cell_index_ptr, "cell_index" current_cell_ptr = builder.gep program.cell_type, program.cells_ptr, cell_index, "current_cell_ptr" cell_val = builder.load program.cell_type, current_cell_ptr, "cell_value" increment_amount = program.cell_type.const_int(@amount) new_cell_val = builder.add cell_val, increment_amount, "cell_value" builder.store new_cell_val, current_cell_ptr bb end end class DataIncrement < Instruction def initialize(@amount : Int32) end def compile(program, bb) builder = program.builder builder.position_at_end bb cell_index = builder.load program.ctx.int32, program.cell_index_ptr, "cell_index" increment_amount = program.ctx.int32.const_int(@amount) new_cell_index = builder.add cell_index, increment_amount, "new_cell_index" builder.store new_cell_index, program.cell_index_ptr bb end end class Read < Instruction def compile(program, bb) builder = program.builder builder.position_at_end bb cell_index = builder.load program.ctx.int32, program.cell_index_ptr, "cell_index" current_cell_ptr = builder.gep program.cell_type, program.cells_ptr, cell_index, "current_cell_ptr" input_char = program.call_c_function "getchar", name: "input_char" input_byte = builder.trunc input_char, program.ctx.int8, "input_byte" builder.store input_byte, current_cell_ptr bb end end class Write < Instruction def compile(program, bb) builder = program.builder builder.position_at_end bb cell_index = builder.load program.ctx.int32, program.cell_index_ptr, "cell_index" current_cell_ptr = builder.gep program.cell_type, program.cells_ptr, cell_index, "current_cell_ptr" cell_val = builder.load program.cell_type, current_cell_ptr, "cell_value" cell_val_as_char = builder.sext cell_val, program.ctx.int32, "cell_val_as_char" program.call_c_function "putchar", cell_val_as_char bb end end class Loop < Instruction def initialize(@body : Array(Instruction)) end def compile(program, bb) builder = program.builder func = program.func loop_header = func.basic_blocks.append "loop_header" builder.position_at_end bb builder.br loop_header loop_body_block = func.basic_blocks.append "loop_body" loop_after = func.basic_blocks.append "loop_after" builder.position_at_end loop_header cell_index = builder.load program.ctx.int32, program.cell_index_ptr, "cell_index" current_cell_ptr = builder.gep program.cell_type, program.cells_ptr, cell_index, "current_cell_ptr" cell_val = builder.load program.cell_type, current_cell_ptr, "cell_value" zero = program.cell_type.const_int(0) cell_val_is_zero = builder.icmp LLVM::IntPredicate::EQ, cell_val, zero builder.cond cell_val_is_zero, loop_after, loop_body_block @body.each do |instruction| loop_body_block = instruction.compile(program, loop_body_block) end builder.position_at_end loop_body_block builder.br loop_header loop_after end end class Program getter mod : LLVM::Module getter ctx : LLVM::Context getter builder : LLVM::Builder getter instructions getter cell_type : LLVM::Type getter! cells_ptr : LLVM::Value getter! cell_index_ptr : LLVM::Value getter! func : LLVM::Function @func_types = {} of String => LLVM::Type def initialize(@instructions : Array(Instruction)) @ctx = LLVM::Context.new @mod = @ctx.new_module("brainfuck") @builder = @ctx.new_builder @cell_type = @ctx.int(CELL_SIZE_IN_BYTES * 8) end def self.new(source : String) new source.chars end def self.new(source : Array(Char)) new parse(source, 0, source.size) end def self.parse(source, from, to) program = [] of Instruction i = from while i < to case source[i] when '+' program << Increment.new(1) when '-' program << Increment.new(-1) when '>' program << DataIncrement.new(1) when '<' program << DataIncrement.new(-1) when ',' program << Read.new when '.' program << Write.new when '[' matching_close_index = find_matching_close(source, i) unless matching_close_index abort "Unmatched '[' at position #{i}" end program << Loop.new(parse(source, i + 1, matching_close_index)) i = matching_close_index when ']' abort "Unmatched ']' at position #{i}" else # skip end i += 1 end program end def self.find_matching_close(source, open_index) open_count = 0 (open_index...source.size).each do |i| case source[i] when '[' open_count += 1 when ']' open_count -= 1 end if open_count == 0 return i end end nil end def compile declare_c_functions mod @func = create_main mod bb = func.basic_blocks.append "entry" add_cells_init mod, bb instructions.each do |instruction| bb = instruction.compile(self, bb) end add_cells_cleanup mod, bb mod end def declare_c_functions(mod) declare_c_function mod, "calloc", [@ctx.int32, @ctx.int32], @ctx.void_pointer declare_c_function mod, "free", [@ctx.void_pointer], @ctx.void declare_c_function mod, "putchar", [@ctx.int32], @ctx.int32 declare_c_function mod, "getchar", ([] of LLVM::Type), @ctx.int32 end def declare_c_function(mod, name, param_types, return_type) func_type = LLVM::Type.function(param_types, return_type) @func_types[name] = func_type mod.functions.add name, func_type end def call_c_function(func_name, args = [] of LLVM::Value, name = "") func = mod.functions[func_name] @builder.call @func_types[func_name], func, args, name end def create_main(mod) main = mod.functions.add "main", ([] of LLVM::Type), @ctx.int32 main.linkage = LLVM::Linkage::External main end def add_cells_init(mod, bb) builder.position_at_end bb call_args = [@ctx.int32.const_int(NUM_CELLS), @ctx.int32.const_int(CELL_SIZE_IN_BYTES)] @cells_ptr = call_c_function "calloc", call_args, "cells" @cell_index_ptr = builder.alloca @ctx.int32, "cell_index_ptr" zero = @ctx.int32.const_int(0) builder.store zero, cell_index_ptr end def add_cells_cleanup(mod, bb) builder.position_at_end bb call_c_function "free", cells_ptr zero = @ctx.int32.const_int(0) builder.ret zero end end def get_output_name(filename) if filename.ends_with?(".bf") "#{filename[0..filename.size - 4]}.ll" else "#{filename}.ll" end end filename = ARGV.first? unless filename abort "Missing filename" end unless File.file?(filename) abort "#{filename} is not a file" end source = File.read(filename) program = Program.new(source) mod = program.compile output_name = get_output_name(filename) File.open(output_name, "w") do |file| mod.to_s(file) end ================================================ FILE: samples/mandelbrot.cr ================================================ def print_density(d) if d > 8 print ' ' elsif d > 4 print '.' elsif d > 2 print '*' else print '+' end end def mandelconverger(real, imag, iters, creal, cimag) if iters > 255 || real*real + imag*imag >= 4 iters else mandelconverger real*real - imag*imag + creal, 2*real*imag + cimag, iters + 1, creal, cimag end end def mandelconverge(real, imag) mandelconverger real, imag, 0, real, imag end def mandelhelp(xmin, xmax, xstep, ymin, ymax, ystep) ymin.step(to: ymax, by: ystep) do |y| xmin.step(to: xmax, by: xstep) do |x| print_density mandelconverge(x, y) end puts end end def mandel(realstart, imagstart, realmag, imagmag) mandelhelp realstart, realstart + realmag*78, realmag, imagstart, imagstart + imagmag*40, imagmag end mandel -2.3, -1.3, 0.05, 0.07 ================================================ FILE: samples/mandelbrot2.cr ================================================ require "complex" def mandelbrot(a) Iterator.of(a).first(100).reduce(a) { |z, c| z*z + c } end (1.0).step(to: -1, by: -0.05) do |y| (-2.0).step(to: 0.5, by: 0.0315) do |x| print mandelbrot(x + y.i).abs < 2 ? '*' : ' ' end puts end ================================================ FILE: samples/matmul.cr ================================================ # Copied with little modifications from: https://github.com/attractivechaos/plb/blob/master/matmul/matmul_v1.rb def matmul(a, b) m = a.size n = a[0].size p = b[0].size # transpose b2 = Array.new(n) { Array.new(p, 0.0) } (0...n).each do |i| (0...p).each do |j| b2[j][i] = b[i][j] end end # multiplication c = Array.new(m) { Array.new(p, 0.0) } (0...m).each do |i| (0...p).each do |j| s = 0.0 ai, b2j = a[i], b2[j] (0...n).each do |k| s += ai[k] * b2j[k] end c[i][j] = s end end c end def matgen(n) tmp = 1.0 / n / n a = Array.new(n) { Array.new(n, 0.0) } (0...n).each do |i| (0...n).each do |j| a[i][j] = tmp * (i - j) * (i + j) end end a end n = (ARGV[0]? || 500).to_i n = n // 2 * 2 a = matgen(n) b = matgen(n) c = matmul(a, b) puts c[n // 2][n // 2] ================================================ FILE: samples/meteor.cr ================================================ # Translated from: https://gitlab.redox-os.org/redox-os/rust/blob/a59de37e99060162a2674e3ff45409ac73595c0e/src/test/bench/shootout-meteor.rs alias Masks = Array(Array(Array(UInt64))) alias Point = Tuple(Int32, Int32) class MyIterator(T) include Enumerable(T) def initialize(@data : T, &@block : T -> T) end def each(&) while true yield @data @data = @block.call(@data) end end end def bo(offset) # bit offset 1_u64 << offset end def bm(mask, offset) # bit mask mask & bo(offset) end def transform(piece, all) i = MyIterator.new piece, &.map { |(y, x)| {x + y, -y} } rots = i.first(all ? 6 : 3) res = rots.flat_map do |cur_piece| i2 = MyIterator.new cur_piece, &.map { |(y, x)| {x, y} } i2.first(2) end res.map do |cur_piece| dy, dx = cur_piece.min cur_piece.map do |(y, x)| {y - dy, x - dx} end end end def mask(dy, dx, id, p) m = bo(50 + id) p.each do |(y, x)| x2 = x + dx + (y + (dy % 2)) // 2 return if x2 < 0 || x2 > 4 y2 = y + dy return if y2 < 0 || y2 > 9 m |= bo(y2 * 5 + x2) end m end PIECES = [ [{0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 3}], [{0, 0}, {0, 2}, {0, 3}, {1, 0}, {1, 1}], [{0, 0}, {0, 1}, {0, 2}, {1, 2}, {2, 1}], [{0, 0}, {0, 1}, {0, 2}, {1, 1}, {2, 1}], [{0, 0}, {0, 2}, {1, 0}, {1, 1}, {2, 1}], [{0, 0}, {0, 1}, {0, 2}, {1, 1}, {1, 2}], [{0, 0}, {0, 1}, {1, 1}, {1, 2}, {2, 1}], [{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 2}], [{0, 0}, {0, 1}, {0, 2}, {1, 2}, {1, 3}], [{0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 2}], ] def make_masks res = Masks.new PIECES.each_with_index do |p, id| trans = transform(p, id != 3) cur_piece = [] of Array(UInt64) 10.times do |dy| 5.times do |dx| cur_piece << trans.compact_map { |t| mask(dy, dx, id, t) } end end res << cur_piece end res end def board_unfeasible?(board : UInt64, masks : Masks) coverable = board (0...50).select { |i| bm(board, i) == 0 }.each do |i| masks.each_with_index do |pos_masks, cur_id| next if bm(board, 50 + cur_id) != 0 pos_masks[i].each do |cur_m| coverable |= cur_m if cur_m & board == 0 end end return true if bm(coverable, i) == 0 end coverable != (bo(60) - 1) end def filter_masks(masks : Masks) masks.map do |p| p.map do |p2| p2.select do |m| !board_unfeasible?(m, masks) end end end end def get_id(m : UInt64) 10.times do |id| return id.to_u8 if bm(m, id + 50) != 0 end raise "Does not have a valid identifier" end def to_utf8(raw_sol) String.new(50) do |buf| raw_sol.each do |m| id = get_id(m) 50.times do |i| buf[i] = '0'.ord.to_u8 + id if bm(m, i) != 0 end end {50, 50} end end def print_sol(str) i = 0 str.each_byte do |c| puts if i % 5 == 0 print ' ' if (i + 5) % 10 == 0 print ' ' print c.chr i += 1 end puts end class SolutionNode def initialize(@x : UInt64, @prev : SolutionNode?) end getter :x getter :prev def each(&) yield @x p = prev while y = p yield y.x p = p.prev end end end class Meteor def initialize(@masks : Masks, @stop_after : Int32) @nb = 0 @min = "9" * 50 @max = "0" * 50 end property min : String property max : String property :nb def handle_sol(cur) @nb += 2 sol1 = to_utf8(cur) sol2 = sol1.reverse @min = {sol1, sol2, @min}.min @max = {sol1, sol2, @max}.max nb < @stop_after end def search(board, i, cur = nil) while bm(board, i) != 0 && (i < 50) i += 1 end return handle_sol(cur) if i >= 50 && cur (0...10).each do |id| if bm(board, id + 50) == 0 @masks[id][i].each do |m| if board & m == 0 return false if !search(board | m, i + 1, SolutionNode.new(m, cur)) end end end end true end end stop_after = (ARGV[0]? || 2098).to_i masks = filter_masks(make_masks) data = Meteor.new(masks, stop_after) data.search(0_u64, 0) puts "#{data.nb} solutions found" print_sol(data.min) print_sol(data.max) puts ================================================ FILE: samples/mt_gc_test.cr ================================================ # Experiment to stress the GC with multi-threading. # The experiment manually allocates multiple times a queue of fibers # on a list of worker threads. The main thread does the orchestration. # The fibers will grow and shrink their stack size by doing recursion. # In each level of the stack an amount of dummy objects are allocated. # These objects will be released by the GC eventually. require "option_parser" require "benchmark" lib LibC fun fflush(b : Void*) end class Foo @@collections = Atomic(Int32).new(0) @data = StaticArray(Int32, 8).new(0) def finalize @@collections.add(1) end def self.collections @@collections.get end end class Context enum State Wait Run end property expected_depth : Int32 = 0 @worker_fibers = Array(Fiber).new(0) def initialize(@fibers : Int32, @threads : Int32, @log : Bool) @fibers_reached = Atomic(Int32).new(0) @threads_reached = Atomic(Int32).new(0) @fiber_depths = Array(Int32).new(@fibers, 0) @pending_fibers_queues = Array(Array(Fiber)).new(@threads) { Array(Fiber).new } @threads_state = Atomic(State).new(State::Wait) # Create worker fibers but do not start them yet. # Each fiber will try to reach the `expected_depth` value # by increasing or decreasing its callstack. @fibers.times do |index| @worker_fibers << Fiber.new("f:#{index}") do Context.fiber_run(self, index, 1) end end # Create worker threads. # they will perform operations when `@threads_state == :run` # otherwise they will remain in a tight busy loop. # See Context#create_thread @threads.times { |index| create_thread(index) } end def self.fiber_run(context, fiber_index, depth) context.set_fiber_depth(fiber_index, depth) # allocate a bunch of objects in the stack # some should be released fast 10.times do foo = Foo.new end foo = Foo.new # increase/decrease stack depending on the expected_depth # when reached, notify and yield control while true if context.expected_depth < depth return elsif context.expected_depth > depth fiber_run(context, fiber_index, depth + 1) else context.notify_depth_reached context.yield end end end def set_fiber_depth(index, depth) @fiber_depths[index] = depth end def run_until_depth(phase, depth) # make all fibers reach a specific depth log "#{phase}: expected_depth: #{depth}" @expected_depth = depth @fibers_reached.set(0) @threads_reached.set(0) # allocate fibers on each thread queue. @pending_fibers_queues.each &.clear @worker_fibers.dup.shuffle!.each_with_index do |f, index| @pending_fibers_queues[index % @threads] << f end @threads_state.set(State::Run) # spin wait for all fibers to finish while @fibers_reached.get < @fibers end log "All fibers_reached!" @threads_state.set(State::Wait) # spin wait for threads to finish the round while @threads_reached.get < @threads end log "All threads_reached!" end def notify_depth_reached @fibers_reached.add(1) end def yield Thread.current.main_fiber.resume end def pick_and_resume_fiber(queue_index) fiber = @pending_fibers_queues[queue_index].shift? if fiber fiber.resume true else false end end def gc_stats log "GC.stats: #{GC.stats}" log "Foo.collections: #{Foo.collections}" end def create_thread(queue_index) Thread.new do # this loop will iterate once per #run_until_depth while true # wait for queues to be ready while @threads_state.get != State::Run end # consume the queue until empty while pick_and_resume_fiber(queue_index) end # wait for all worker threads to finish while @threads_state.get != State::Wait end # sync all workers threads end of loop @threads_reached.add(1) end end end def log(s) if @log t = Thread.current.to_s rescue "Unknown" f = Fiber.current.to_s rescue "Unknown" LibC.printf("%s::%s >>> %s\n", t, f, s) LibC.fflush(nil) end s end end def run(threads_num, fibers_num, loops_num, log) # Specify the number of fibers and threads to use context = Context.new(fibers: fibers_num, threads: threads_num, log: log) (1..loops_num).each do |i| context.run_until_depth "Phase #{i}.1", 40 context.run_until_depth "Phase #{i}.2", 5 context.gc_stats context.run_until_depth "Phase #{i}.3", 50 context.run_until_depth "Phase #{i}.4", 5 context.gc_stats context.run_until_depth "Phase #{i}.5", 10 context.gc_stats end context.log "Done" end enum Mode Run Ips Measure end threads_num = 4 fibers_num = 1_000 loops_num = 20 mode : Mode = :run OptionParser.parse do |parser| parser.on("-i", "--ips", "Benchmark with ips") { mode = :ips } parser.on("-m", "--measure", "Benchmark with measure") { mode = :measure } parser.on("-f FIBERS", "--fibers=FIBERS", "Specifies the number of fibers") { |v| fibers_num = v.to_i } parser.on("-t THREADS", "--threads=THREADS", "Specifies the number of threads") { |v| threads_num = v.to_i } parser.on("-l LOOPS", "--loops=LOOPS", "Specifies the number of loops") { |v| loops_num = v.to_i } parser.on("-h", "--help", "Show this help") { puts parser exit(0) } parser.invalid_option do |flag| STDERR.puts "ERROR: #{flag} is not a valid option." STDERR.puts parser exit(1) end end case mode when .run? run(threads_num, fibers_num, loops_num, true) when .ips? Benchmark.ips do |x| x.report("run") { run(threads_num, fibers_num, loops_num, false) } end when .measure? puts Benchmark.measure { run(threads_num, fibers_num, loops_num, false) } end ================================================ FILE: samples/nbodies.cr ================================================ # Copied with little modifications from: https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/nbody-yarv-2.html SOLAR_MASS = 4 * Math::PI**2 DAYS_PER_YEAR = 365.24 class Planet property x : Float64 property y : Float64 property z : Float64 property vx : Float64 property vy : Float64 property vz : Float64 property mass : Float64 def initialize(@x, @y, @z, vx, vy, vz, mass) @vx, @vy, @vz = vx * DAYS_PER_YEAR, vy * DAYS_PER_YEAR, vz * DAYS_PER_YEAR @mass = mass * SOLAR_MASS end def move_from_i(bodies, nbodies, dt, i) while i < nbodies b2 = bodies[i] dx = @x - b2.x dy = @y - b2.y dz = @z - b2.z distance = Math.sqrt(dx * dx + dy * dy + dz * dz) mag = dt / (distance * distance * distance) b_mass_mag, b2_mass_mag = @mass * mag, b2.mass * mag @vx -= dx * b2_mass_mag @vy -= dy * b2_mass_mag @vz -= dz * b2_mass_mag b2.vx += dx * b_mass_mag b2.vy += dy * b_mass_mag b2.vz += dz * b_mass_mag i += 1 end @x += dt * @vx @y += dt * @vy @z += dt * @vz end end def energy(bodies) e = 0.0 nbodies = bodies.size 0.upto(nbodies - 1) do |i| b = bodies[i] e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz) (i + 1).upto(nbodies - 1) do |j| b2 = bodies[j] dx = b.x - b2.x dy = b.y - b2.y dz = b.z - b2.z distance = Math.sqrt(dx * dx + dy * dy + dz * dz) e -= (b.mass * b2.mass) / distance end end e end def offset_momentum(bodies) px, py, pz = 0.0, 0.0, 0.0 bodies.each do |b| m = b.mass px += b.vx * m py += b.vy * m pz += b.vz * m end b = bodies[0] b.vx = -px / SOLAR_MASS b.vy = -py / SOLAR_MASS b.vz = -pz / SOLAR_MASS end BODIES = [ # sun Planet.new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0), # jupiter Planet.new( 4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01, 1.66007664274403694e-03, 7.69901118419740425e-03, -6.90460016972063023e-05, 9.54791938424326609e-04), # saturn Planet.new( 8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01, -2.76742510726862411e-03, 4.99852801234917238e-03, 2.30417297573763929e-05, 2.85885980666130812e-04), # uranus Planet.new( 1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01, 2.96460137564761618e-03, 2.37847173959480950e-03, -2.96589568540237556e-05, 4.36624404335156298e-05), # neptune Planet.new( 1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01, 2.68067772490389322e-03, 1.62824170038242295e-03, -9.51592254519715870e-05, 5.15138902046611451e-05), ] if ARGV.size != 1 abort "Usage: nbodies n" end n = ARGV[0].to_i offset_momentum(BODIES) puts energy(BODIES) nbodies = BODIES.size dt = 0.01 n.times do i = 0 while i < nbodies b = BODIES[i] b.move_from_i(BODIES, nbodies, dt, i + 1) i += 1 end end puts energy(BODIES) ================================================ FILE: samples/neural_net.cr ================================================ # Copied with little modifications from: https://github.com/jruby/rubybench/blob/master/time/bench_neural_net.rb class Synapse property weight : Float64 property prev_weight : Float64 property :source_neuron property :dest_neuron def initialize(@source_neuron : Neuron, @dest_neuron : Neuron) @prev_weight = @weight = rand * 2 - 1 end end class Neuron LEARNING_RATE = 1.0 MOMENTUM = 0.3 property :synapses_in property :synapses_out property threshold : Float64 property prev_threshold : Float64 property :error property :output def initialize @prev_threshold = @threshold = rand * 2 - 1 @synapses_in = [] of Synapse @synapses_out = [] of Synapse @output = 0.0 @error = 0.0 end def calculate_output activation = synapses_in.reduce(0.0) do |sum, synapse| sum + synapse.weight * synapse.source_neuron.output end activation -= threshold @output = 1.0 / (1.0 + Math.exp(-activation)) end def derivative output * (1 - output) end def output_train(rate, target) @error = (target - output) * derivative update_weights(rate) end def hidden_train(rate) @error = synapses_out.reduce(0.0) do |sum, synapse| sum + synapse.prev_weight * synapse.dest_neuron.error end * derivative update_weights(rate) end def update_weights(rate) synapses_in.each do |synapse| temp_weight = synapse.weight synapse.weight += (rate * LEARNING_RATE * error * synapse.source_neuron.output) + (MOMENTUM * (synapse.weight - synapse.prev_weight)) synapse.prev_weight = temp_weight end temp_threshold = threshold @threshold += (rate * LEARNING_RATE * error * -1) + (MOMENTUM * (threshold - prev_threshold)) @prev_threshold = temp_threshold end end class NeuralNetwork @input_layer : Array(Neuron) @hidden_layer : Array(Neuron) @output_layer : Array(Neuron) def initialize(inputs, hidden, outputs) @input_layer = (1..inputs).map { Neuron.new } @hidden_layer = (1..hidden).map { Neuron.new } @output_layer = (1..outputs).map { Neuron.new } @input_layer.each_cartesian(@hidden_layer) do |source, dest| synapse = Synapse.new(source, dest) source.synapses_out << synapse dest.synapses_in << synapse end @hidden_layer.each_cartesian(@output_layer) do |source, dest| synapse = Synapse.new(source, dest) source.synapses_out << synapse dest.synapses_in << synapse end end def train(inputs, targets) feed_forward(inputs) @output_layer.zip(targets) do |neuron, target| neuron.output_train(0.3, target) end @hidden_layer.each do |neuron| neuron.hidden_train(0.3) end end def feed_forward(inputs) @input_layer.zip(inputs) do |neuron, input| neuron.output = input.to_f64 end @hidden_layer.each do |neuron| neuron.calculate_output if neuron end @output_layer.each do |neuron| neuron.calculate_output if neuron end end def current_outputs @output_layer.map do |neuron| neuron.output end end end (ARGV[0]? || 5).to_i.times do xor = NeuralNetwork.new(2, 10, 1) 10000.times do xor.train([0, 0], [0]) xor.train([1, 0], [1]) xor.train([0, 1], [1]) xor.train([1, 1], [0]) end xor.feed_forward([0, 0]) puts xor.current_outputs xor.feed_forward([0, 1]) puts xor.current_outputs xor.feed_forward([1, 0]) puts xor.current_outputs xor.feed_forward([1, 1]) puts xor.current_outputs end ================================================ FILE: samples/noise.cr ================================================ # Perlin noise benchmark: https://github.com/nsf/pnoise record Vec2, x : Float64, y : Float64 def lerp(a, b, v) a * (1.0 - v) + b * v end def smooth(v) v * v * (3.0 - 2.0 * v) end def random_gradient v = rand * Math::PI * 2.0 Vec2.new(Math.cos(v), Math.sin(v)) end def gradient(orig, grad, p) sp = Vec2.new(p.x - orig.x, p.y - orig.y) grad.x * sp.x + grad.y * sp.y end struct Noise2DContext def initialize @rgradients = StaticArray(Vec2, 256).new { random_gradient } @permutations = StaticArray(Int32, 256).new { |i| i } @permutations.shuffle! end def get_gradient(x, y) idx = @permutations[x & 255] + @permutations[y & 255] @rgradients[idx & 255] end def get_gradients(x, y) x0f = x.floor y0f = y.floor x0 = x0f.to_i y0 = y0f.to_i x1 = x0 + 1 y1 = y0 + 1 { { get_gradient(x0, y0), get_gradient(x1, y0), get_gradient(x0, y1), get_gradient(x1, y1), }, { Vec2.new(x0f + 0.0, y0f + 0.0), Vec2.new(x0f + 1.0, y0f + 0.0), Vec2.new(x0f + 0.0, y0f + 1.0), Vec2.new(x0f + 1.0, y0f + 1.0), }, } end def get(x, y) p = Vec2.new(x, y) gradients, origins = get_gradients(x, y) v0 = gradient(origins[0], gradients[0], p) v1 = gradient(origins[1], gradients[1], p) v2 = gradient(origins[2], gradients[2], p) v3 = gradient(origins[3], gradients[3], p) fx = smooth(x - origins[0].x) vx0 = lerp(v0, v1, fx) vx1 = lerp(v2, v3, fx) fy = smooth(y - origins[0].y) lerp(vx0, vx1, fy) end end symbols = [' ', '░', '▒', '▓', '█', '█'] pixels = Array.new(256) { Array.new(256, 0.0) } n2d = Noise2DContext.new 100.times do |i| 256.times do |y| 256.times do |x| v = n2d.get(x * 0.1, (y + (i * 128)) * 0.1) * 0.5 + 0.5 pixels[y][x] = v end end end 256.times do |y| 256.times do |x| v = pixels[y][x] print(symbols[(v / 0.2).to_i]) end puts end ================================================ FILE: samples/pig.cr ================================================ # Translated from Go: http://golang.org/doc/codewalk/functions/ Win = 100 # The winning score in a game of Pig GamesPerSeries = 10 # The number of games per series to simulate # A score includes scores accumulated in previous turns for each player, # as well as the points scored by the current player in this turn. record Score, player : Int32, opponent : Int32, this_turn : Int32 # roll returns the {result, turn_is_over} outcome of simulating a die roll. # If the roll value is 1, then this_turn score is abandoned, and the players' # roles swap. Otherwise, the roll value is added to this_turn. def roll(s) outcome = rand 1..6 if outcome == 1 {Score.new(s.opponent, s.player, 0), true} else {Score.new(s.player, s.opponent, outcome + s.this_turn), false} end end # stay returns the {result, turn_is_over} outcome of staying. # this_turn score is added to the player's score, and the players' roles swap. def stay(s) {Score.new(s.opponent, s.player + s.this_turn, 0), true} end # stay_at_k returns a strategy that rolls until this_turn is at least k, then stays. def stay_at_k(k) ->(s : Score) do if s.this_turn >= k ->stay(Score) else ->roll(Score) end end end # play simulates a Pig game and returns the winner (0 or 1). def play(strategy0, strategy1) strategies = {strategy0, strategy1} s = Score.new(0, 0, 0) turn_is_over = false current_player = rand(2) while s.player + s.this_turn < Win action = strategies[current_player].call(s) s, turn_is_over = action.call(s) if turn_is_over current_player = (current_player + 1) % 2 end end current_player end # roundRobin simulates a series of games between every pair of strategies. def round_robin(strategies) wins = Array.new(strategies.size, 0) (0...strategies.size).each do |i| (i + 1...strategies.size).each do |j| (0...GamesPerSeries).each do |k| winner = play strategies[i], strategies[j] if winner == 0 wins[i] += 1 else wins[j] += 1 end end end end games_per_strategy = GamesPerSeries * (strategies.size - 1) {wins, games_per_strategy} end # ratio_string takes a list of integer values and returns a string that lists # each value and its percentage of the sum of all values. # e.g., ratios(1, 2, 3) = "1/6 (16.7%), 2/6 (33.3%), 3/6 (50.0%)" def ratio_string(vals) total = vals.sum vals.map do |val| pct = ((100 * val.to_f / total.to_f) * 10).to_i / 10.0 "#{val}/#{total} %#{pct}" end.join ", " end strategies = Array.new(Win) { |k| stay_at_k(k + 1) } wins, games = round_robin strategies strategies.each_with_index do |strategy, k| puts "Wins, losses staying at k = #{k + 1}: #{ratio_string({wins[k], games - wins[k]})}" end ================================================ FILE: samples/pretty_json.cr ================================================ # JSON pretty printer # ~~~~~~~~~~~~~~~~~~~ # # Reads JSON from STDIN and outputs it formatted and colored to STDOUT. # # Usage: echo '[1, {"two": "three"}, false]' | pretty_json require "json" require "colorize" class PrettyPrinter def initialize(@input : IO, @output : IO) @pull = JSON::PullParser.new @input @indent = 0 end def print read_any end def read_any case @pull.kind when .null? Colorize.with.bold.surround(@output) do @pull.read_null.to_json(@output) end when .bool? Colorize.with.light_blue.surround(@output) do @pull.read_bool.to_json(@output) end when .int? Colorize.with.red.surround(@output) do @pull.read_int.to_json(@output) end when .float? Colorize.with.red.surround(@output) do @pull.read_float.to_json(@output) end when .string? Colorize.with.yellow.surround(@output) do @pull.read_string.to_json(@output) end when .begin_array? read_array when .begin_object? read_object when .eof? # We are done when .end_array?, .end_object? raise "Bug: Shouldn't happen" end end def read_array print "[\n" @indent += 1 i = 0 @pull.read_array do if i > 0 print ',' print '\n' if @indent > 0 end print_indent read_any i += 1 end @indent -= 1 print '\n' print_indent print ']' end def read_object print "{\n" @indent += 1 i = 0 @pull.read_object do |key| if i > 0 print ',' print '\n' if @indent > 0 end print_indent Colorize.with.cyan.surround(@output) do key.to_json(@output) end print ": " read_any i += 1 end @indent -= 1 print '\n' print_indent print '}' end def print_indent @indent.times { @output << " " } end def print(value) @output << value end end printer = PrettyPrinter.new(STDIN, STDOUT) printer.print STDOUT.puts ================================================ FILE: samples/quine.cr ================================================ s = "s = @; puts s.sub(\"@\", s.dump)"; puts s.sub("@", s.dump) ================================================ FILE: samples/red_black_tree.cr ================================================ # Copied with little modifications from: https://github.com/rubinius/rubinius-benchmark/blob/cf4a2468f46d23cc300815afabc8150609383d6c/real_world/bench_red_black_tree.rb class RedBlackTree class Node enum Color Red Black end property color : Color property key : Int32 property! :left property! :right property! parent : self def initialize(@key, @color : Color = :red) @left = @right = @parent = NilNode.instance end def black? color.black? end def red? color.red? end def nil_node? false end end class NilNode < Node def self.instance @@instance ||= RedBlackTree::NilNode.new end def initialize @key = 0 @color = :black @left = @right = @parent = self end def nil_node? true end end property root : Node property :size def initialize @root = NilNode.instance @size = 0 end def add(key) insert(Node.new(key)) end def insert(x) insert_helper(x) x.color = :red while x != root && x.parent.red? if x.parent == x.parent.parent.left y = x.parent.parent.right if !y.nil_node? && y.red? x.parent.color = :black y.color = :black x.parent.parent.color = :red x = x.parent.parent else if x == x.parent.right x = x.parent left_rotate(x) end x.parent.color = :black x.parent.parent.color = :red right_rotate(x.parent.parent) end else y = x.parent.parent.left if !y.nil_node? && y.red? x.parent.color = :black y.color = :black x.parent.parent.color = :red x = x.parent.parent else if x == x.parent.left x = x.parent right_rotate(x) end x.parent.color = :black x.parent.parent.color = :red left_rotate(x.parent.parent) end end end root.color = :black end def <<(x) insert(x) end def delete(z) y = (z.left.nil_node? || z.right.nil_node?) ? z : successor(z) x = y.left.nil_node? ? y.right : y.left x.parent = y.parent if y.parent.nil_node? self.root = x else if y == y.parent.left y.parent.left = x else y.parent.right = x end end z.key = y.key if y != z if y.black? delete_fixup(x) end self.size -= 1 y end def minimum(x = root) while !x.left.nil_node? x = x.left end x end def maximum(x = root) while !x.right.nil_node? x = x.right end x end def successor(x) if !x.right.nil_node? return minimum(x.right) end y = x.parent while !y.nil_node? && x == y.right x = y y = y.parent end y end def predecessor(x) if !x.left.nil_node? return maximum(x.left) end y = x.parent while !y.nil_node? && x == y.left x = y y = y.parent end y end def inorder_walk(&) x = self.minimum while !x.nil_node? yield x.key x = successor(x) end end def each(x = root, &) inorder_walk(x) { |k| yield k } end def reverse_inorder_walk(&) x = self.maximum while !x.nil_node? yield x.key x = predecessor(x) end end def reverse_each(x = root, &) reverse_inorder_walk(x) { |k| yield k } end def search(key, x = root) while !x.nil_node? && x.key != key x = (key < x.key) ? x.left : x.right end x end def empty? self.root.nil_node? end def black_height(x = root) height = 0 while !x.nil_node? x = x.left height += 1 if x.nil_node? || x.black? end height end private def left_rotate(x) raise "x.right is nil!" if x.right.nil_node? y = x.right x.right = y.left y.left.parent = x if !y.left.nil_node? y.parent = x.parent if x.parent.nil_node? self.root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.left = x x.parent = y end private def right_rotate(x) raise "x.left is nil!" if x.left.nil_node? y = x.left x.left = y.right y.right.parent = x if !y.right.nil_node? y.parent = x.parent if x.parent.nil_node? self.root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.right = x x.parent = y end private def insert_helper(z) y = NilNode.instance x = root while !x.nil_node? y = x x = (z.key < x.key) ? x.left : x.right end z.parent = y if y.nil_node? self.root = z else z.key < y.key ? y.left = z : y.right = z end self.size += 1 end private def delete_fixup(x) while x != root && x.black? if x == x.parent.left w = x.parent.right if w.red? w.color = :black x.parent.color = :red left_rotate(x.parent) w = x.parent.right end if w.left.black? && w.right.black? w.color = :red x = x.parent else if w.right.black? w.left.color = :black w.color = :red right_rotate(w) w = x.parent.right end w.color = x.parent.color x.parent.color = :black w.right.color = :black left_rotate(x.parent) x = root end else w = x.parent.left if w.red? w.color = :black x.parent.color = :red right_rotate(x.parent) w = x.parent.left end if w.right.black? && w.left.black? w.color = :red x = x.parent else if w.left.black? w.right.color = :black w.color = :red left_rotate(w) w = x.parent.left end w.color = x.parent.color x.parent.color = :black w.left.color = :black right_rotate(x.parent) x = root end end end x.color = :black end end class RedBlackTreeRunner property :tree def initialize(n = 10_000) @n = n random = Random.new(1234) # repeatable random seq @a1 = Array(Int32).new(n) { random.rand(99_999) } random = Random.new(4321) # repeatable random seq @a2 = Array(Int32).new(n) { random.rand(99_999) } @tree = RedBlackTree.new end def run_delete @tree = RedBlackTree.new @n.times { |i| @tree.add(i) } @n.times { @tree.delete(@tree.root) } tree.size end def run_add @tree = RedBlackTree.new @a1.each { |e| @tree.add(e) } tree.size end def run_search s = c = 0 @a2.each { |e| c += 1; s += @tree.search(e).key % 3 } [s, c] end def run_inorder_walk s = 0 c = 0 @tree.inorder_walk { |key| c += 1; s += key % 3 } [s, c] end def run_reverse_inorder_walk s = 0 c = 0 @tree.reverse_inorder_walk { |key| c += 1; s += key % 3 } [s, c] end def run_min s = 0 @n.times { s += @tree.minimum.key } s end def run_max s = 0_u64 @n.times { s += @tree.maximum.key } s end end def bench(name, n = 1, &) start = Time.monotonic print "#{name}: " res = nil n.times do res = yield end puts "#{Time.monotonic - start}, res: #{res}" end start = Time.monotonic b = RedBlackTreeRunner.new 100_000 bench("delete", 10) { b.run_delete } bench("add", 10) { b.run_add } bench("search", 10) { b.run_search } bench("walk", 100) { b.run_inorder_walk } bench("reverse_walk", 100) { b.run_reverse_inorder_walk } bench("min", 100) { b.run_min } bench("max", 100) { b.run_max } puts "summary time: #{Time.monotonic - start}" ================================================ FILE: samples/sdl/fire.cr ================================================ require "./sdl/sdl" class Point MAX_LIFE = 50 HALF_LIFE = MAX_LIFE / 2 property x : Float64 property y : Float64 property angle : Float64 property speed : Float64 property color_pattern : ColorPattern getter :life def initialize(x, y, angle, speed, color_pattern) @x = x.to_f64 @y = y.to_f64 @angle = angle.to_f64 @speed = speed.to_f64 @color_pattern = color_pattern @life = MAX_LIFE end def dead? @life <= 0 end def revive @life = MAX_LIFE end def die_a_little @life -= 1 end def color @color_pattern.interpolate(@life) end def advance(screen) @x += @speed * Math.cos(@angle) @y -= @speed * Math.sin(@angle) if @x <= 0 @angle = Math::PI - @angle @x = 0_f64 end if @x >= screen.width - 1 @angle = Math::PI - @angle @x = (screen.width - 1).to_f64 end if @y <= 0 @angle = 2 * Math::PI - @angle @y = 0_f64 end if @y >= screen.height - 1 @angle = 2 * Math::PI - @angle @y = (screen.height - 1).to_f64 end end end class MainPoint < Point COUNT = 4 MAX_TAIL_ANGLE = Math::PI / 3 TAIL_SPEED = 0.05 enum Direction Plus Minus end @tail_angle : Float64 @tail_direction : Direction def initialize(x, y, angle, speed, color_pattern) super @tail_angle = MAX_TAIL_ANGLE @tail_direction = :minus @color_pattern = color_pattern end def turn_left @angle += 0.05 end def turn_right @angle -= 0.05 end def speed_up @speed += 0.02 @speed = 20_f64 if @speed >= 20 end def speed_down @speed -= 0.02 @speed = 0_f64 if @speed <= 0 end def color @color_pattern.main end def emit_tail_points(points) points.make(@x, @y, Math::PI + @angle + @tail_angle, @speed, @color_pattern.child) points.make(@x, @y, Math::PI + @angle - @tail_angle, @speed, @color_pattern.child) if @tail_direction.plus? @tail_angle += TAIL_SPEED if @tail_angle >= MAX_TAIL_ANGLE @tail_angle = MAX_TAIL_ANGLE @tail_direction = :minus end else @tail_angle -= TAIL_SPEED if @tail_angle <= -MAX_TAIL_ANGLE @tail_angle = -MAX_TAIL_ANGLE @tail_direction = :plus end end end end abstract class ColorPattern def child self end def interpolate_half(life) (life * 255.0 / Point::HALF_LIFE).to_i end def interpolate_max(life) (life * 255.0 / Point::MAX_LIFE).to_i end def make_color(r, g, b) (b << 24) + (g << 16) + (r << 8) end end class YellowColorPattern < ColorPattern def main 0x00FFFF00 end def interpolate(life) if life > Point::HALF_LIFE r, g, b = 255, interpolate_half(life), 0 else r, g, b = interpolate_half(life), 0, 0 end make_color r, g, b end end class CyanColorPattern < ColorPattern def main 0xFFFF0000 end def interpolate(life) if life > Point::HALF_LIFE r, g, b = 0, 255, interpolate_half(life) else r, g, b = 0, interpolate_half(life), 0 end make_color r, g, b end end class MagentaColorPattern < ColorPattern def main 0xFF00FF00 end def interpolate(life) if life > Point::HALF_LIFE r, g, b = interpolate_half(life), 0, 255 else r, g, b = 0, 0, interpolate_half(life) end make_color r, g, b end end class RainbowColorPattern < ColorPattern def initialize(@patterns : Array(ColorPattern)) @index = 0.0 end def main main = @patterns[@index.to_i].main @index += 0.05 @index = 0.0 if @index.to_i >= @patterns.size main end def child @patterns[@index.to_i] end def interpolate(life) raise "Shouldn't reach here" end end class Points MAX = Point::MAX_LIFE * MainPoint::COUNT * 2 def initialize @points = Array(Point).new(MAX) end def make(x, y, angle, speed, color_pattern) @points.each do |point| if point.dead? point.x = x point.y = y point.angle = angle point.speed = speed point.color_pattern = color_pattern point.revive return end end if @points.size < MAX @points << Point.new(x, y, angle, speed, color_pattern) end end def each(&) @points.each do |point| yield point unless point.dead? end end end record Rectangle, x : Int32, y : Int32 do def contains?(p) contains? p.x, p.y end def contains?(x, y) @x <= x && x < @x + 10 && @y <= y && y < @y + 10 end end def parse_rectangles(filename) unless File.exists?(filename) raise "File does not exist: #{filename}" end rects = [] of Rectangle lines = File.read(filename) lines = lines.split('\n').map(&.rstrip) lines.each_with_index do |line, y| x = 0 line.each_char do |c| if c != ' ' rects << Rectangle.new(x * 10, y * 10) end x += 1 end end rects end class Screen @rects : Array(Rectangle) def initialize(@surface : SDL::Surface) @background = Array(UInt32).new(surface.width * surface.height, 0_u32) @rects = parse_rectangles("#{__DIR__}/fire.txt") end def width @surface.width end def height @surface.height end def put_pixel(point, color) color = color.to_u32! offset = @surface.offset(point.x, point.y) @surface[offset] = color background_intensity = intensity(@background[offset]) color_intensity = intensity(color) if color_intensity >= background_intensity && @rects.any?(&.contains?(point)) @background[offset] = color end end def put_background(point) offset = @surface.offset(point.x, point.y) @surface[offset] = @background[offset] end def intensity(color) b = (color >> 24) % 256 g = (color >> 16) % 256 r = (color >> 8) % 256 r + g + b end end def finish(start, frames) ms = SDL.ticks - start puts "#{frames} frames in #{ms} ms" puts "Average FPS: #{frames / (ms * 0.001)}" SDL.quit exit end width = 640 height = 480 point_count = ARGV.size > 0 ? ARGV[0].to_i : 4 yellow = YellowColorPattern.new magenta = MagentaColorPattern.new cyan = CyanColorPattern.new rainbow = RainbowColorPattern.new [yellow, magenta, cyan] main_points = [] of MainPoint main_points << MainPoint.new(50, 50, -Math::PI / 8, 1.4, yellow) main_points << MainPoint.new(width - 50, height - 50, Math::PI - Math::PI / 8, 1.4, magenta) if point_count >= 2 main_points << MainPoint.new(width - 50, 50, Math::PI + Math::PI / 8, 1.4, cyan) if point_count >= 3 main_points << MainPoint.new(50, height - 50, Math::PI / 8, 1.4, rainbow) if point_count >= 4 points = Points.new SDL.init SDL.hide_cursor surface = SDL.set_video_mode width, height, 32, LibSDL::DOUBLEBUF | LibSDL::HWSURFACE | LibSDL::ASYNCBLIT | LibSDL::FULLSCREEN screen = Screen.new(surface) frames = 0_u32 start = SDL.ticks turn_left = Array.new(MainPoint::COUNT, false) turn_right = Array.new(MainPoint::COUNT, false) speed_up = Array.new(MainPoint::COUNT, false) speed_down = Array.new(MainPoint::COUNT, false) while true SDL.poll_events do |event| case event.type when LibSDL::QUIT finish start, frames when LibSDL::KEYDOWN case event.key.key_sym.sym when LibSDL::Key::ESCAPE, LibSDL::Key::Q finish start, frames when LibSDL::Key::LEFT turn_left[0] = true when LibSDL::Key::RIGHT turn_right[0] = true when LibSDL::Key::UP speed_up[0] = true when LibSDL::Key::DOWN speed_down[0] = true when LibSDL::Key::W speed_up[1] = true when LibSDL::Key::A turn_left[1] = true when LibSDL::Key::S speed_down[1] = true when LibSDL::Key::D turn_right[1] = true when LibSDL::Key::T speed_up[2] = true when LibSDL::Key::F turn_left[2] = true when LibSDL::Key::G speed_down[2] = true when LibSDL::Key::H turn_right[2] = true when LibSDL::Key::I speed_up[3] = true when LibSDL::Key::J turn_left[3] = true when LibSDL::Key::K speed_down[3] = true when LibSDL::Key::L turn_right[3] = true end when LibSDL::KEYUP case event.key.key_sym.sym when LibSDL::Key::LEFT turn_left[0] = false when LibSDL::Key::RIGHT turn_right[0] = false when LibSDL::Key::UP speed_up[0] = false when LibSDL::Key::DOWN speed_down[0] = false when LibSDL::Key::W speed_up[1] = false when LibSDL::Key::A turn_left[1] = false when LibSDL::Key::S speed_down[1] = false when LibSDL::Key::D turn_right[1] = false when LibSDL::Key::T speed_up[2] = false when LibSDL::Key::F turn_left[2] = false when LibSDL::Key::G speed_down[2] = false when LibSDL::Key::H turn_right[2] = false when LibSDL::Key::I speed_up[3] = false when LibSDL::Key::J turn_left[3] = false when LibSDL::Key::K speed_down[3] = false when LibSDL::Key::L turn_right[3] = false end end end surface.lock points.each do |point| screen.put_background(point) point.die_a_little end main_points.each do |main_point| screen.put_background(main_point) end main_points.each_with_index do |main_point, i| main_point.turn_left if turn_left[i] main_point.turn_right if turn_right[i] main_point.speed_up if speed_up[i] main_point.speed_down if speed_down[i] main_point.advance(screen) end points.each do |point| point.advance(screen) end points.each do |point| screen.put_pixel(point, point.color) end main_points.each do |main_point| screen.put_pixel(main_point, main_point.color) end main_points.each do |main_point| main_point.emit_tail_points(points) end surface.unlock surface.flip frames += 1 end ================================================ FILE: samples/sdl/fire.txt ================================================ xxxxxx xxxxx xx xx xxxxxx xxxxxx xxxxxx xx xxxxxx xxxxxx xx xx xxxxxx xxxxxx xxxxxx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xxxxxx xx xx xx xx xx xx xxxxxx xxxxxx xxxxxx xx xxxxxx xx xx xxxxx xx xxxxxx xx xxxxxx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xxxxxx xx xx xx xxxxxx xx xx xx xxxxxx xxxxxx xx xx xx xxxxxx xx xx xx xxxxxx ================================================ FILE: samples/sdl/raytracer.cr ================================================ # Ported from Nimrod: https://gist.github.com/AdrianV/5774141 require "./sdl/sdl" WIDTH = 1280 HEIGHT = 720 FOV = 45.0 MAX_DEPTH = 6 struct Vec3 getter :x getter :y getter :z def initialize @x, @y, @z = 0.0, 0.0, 0.0 end def initialize(value) @x, @y, @z = value, value, value end def initialize(@x, @y, @z) end {% for op in %w(+ - * /) %} def {{op.id}}(other : Vec3) Vec3.new(@x {{op.id}} other.x, @y {{op.id}} other.y, @z {{op.id}} other.z) end def {{op.id}}(other : Float) Vec3.new(@x {{op.id}} other, @y {{op.id}} other, @z {{op.id}} other) end {% end %} def - Vec3.new(-@x, -@y, -@z) end def dot(other) @x * other.x + @y * other.y + @z * other.z end def magnitude Math.sqrt(dot(self)) end def normalize m = magnitude Vec3.new(@x / m, @y / m, @z / m) end end record Ray, start : Vec3, dir : Vec3 class Sphere getter :color getter :reflection getter :transparency def initialize(@center : Vec3, @radius : Float64, @color : Vec3, @reflection = 0.0, @transparency = 0.0) end def intersects?(ray) vl = @center - ray.start a = vl.dot(ray.dir) return false if a < 0 b2 = vl.dot(vl) - a * a r2 = @radius * @radius return false if b2 > r2 true end def intersect(ray, distance) vl = @center - ray.start a = vl.dot(ray.dir) return nil if a < 0 b2 = vl.dot(vl) - a * a r2 = @radius * @radius return nil if b2 > r2 c = Math.sqrt(r2 - b2) near = a - c far = a + c near < 0 ? far : near end def normalize(v) (v - @center).normalize end end record Light, position : Vec3, color : Vec3 record Scene, objects : Array(Sphere), lights : Array(Light) def trace(ray, scene, depth) nearest = 1e9 obj = nil result = Vec3.new scene.objects.each do |o| distance = 1e9 if (distance = o.intersect(ray, distance)) && distance < nearest nearest = distance obj = o end end if obj point_of_hit = ray.dir * nearest point_of_hit += ray.start normal = obj.normalize(point_of_hit) inside = false dot_normal_ray = normal.dot(ray.dir) if dot_normal_ray > 0 inside = true normal = -normal dot_normal_ray = -dot_normal_ray end reflection_ratio = obj.reflection norm_e5 = normal * 1.0e-5 scene.lights.each do |lgt| light_direction = (lgt.position - point_of_hit).normalize r = Ray.new(point_of_hit + norm_e5, light_direction) # go through the scene check whether we're blocked from the lights blocked = scene.objects.any? &.intersects? r unless blocked temp = lgt.color temp *= Math.max(0.0, normal.dot(light_direction)) temp *= obj.color temp *= (1.0 - reflection_ratio) result += temp end end facing = Math.max(0.0, -dot_normal_ray) fresneleffect = reflection_ratio + (1.0 - reflection_ratio) * ((1.0 - facing) ** 5.0) # compute reflection if depth < MAX_DEPTH && reflection_ratio > 0 reflection_direction = ray.dir - normal * 2.0 * dot_normal_ray reflection = trace(Ray.new(point_of_hit + norm_e5, reflection_direction), scene, depth + 1) result += reflection * fresneleffect end # compute refraction if depth < MAX_DEPTH && (obj.transparency > 0.0) ior = 1.5 ce = ray.dir.dot(normal) * -1.0 ior = inside ? 1.0 / ior : ior eta = 1.0 / ior gf = (ray.dir + normal * ce) * eta sin_t1_2 = 1.0 - ce * ce sin_t2_2 = sin_t1_2 * (eta * eta) if sin_t2_2 < 1.0 gc = normal * Math.sqrt(1 - sin_t2_2) refraction_direction = gf - gc refraction = trace(Ray.new(point_of_hit - normal * 1.0e-4, refraction_direction), scene, depth + 1) result += refraction * (1.0 - fresneleffect) * obj.transparency end end end result end def render(scene, surface) surface.lock eye = Vec3.new h = Math.tan(FOV / 360.0 * 2.0 * Math::PI / 2.0) * 2.0 ww = surface.width.to_f64 hh = surface.height.to_f64 w = h * ww / hh i = 0 HEIGHT.times do |y| yy = y.to_f64 WIDTH.times do |x| xx = x.to_f64 dir = Vec3.new((xx - ww / 2.0) / ww * w, (hh / 2.0 - yy) / hh * h, -1.0).normalize pixel = trace(Ray.new(eye, dir), scene, 0.0) r = Math.min(255, (pixel.x * 255.0).round.to_i) g = Math.min(255, (pixel.y * 255.0).round.to_i) b = Math.min(255, (pixel.z * 255.0).round.to_i) surface[i] = (b << 24) + (g << 16) + (r << 8) i += 1 end end surface.unlock surface.update_rect 0, 0, 0, 0 end Process.on_interrupt { exit } scene = Scene.new( [ Sphere.new(Vec3.new(0.0, -10002.0, -20.0), 10000.0, Vec3.new(0.8, 0.8, 0.8)), Sphere.new(Vec3.new(0.0, 2.0, -20.0), 4.0, Vec3.new(0.8, 0.5, 0.5), 0.5), Sphere.new(Vec3.new(5.0, 0.0, -15.0), 2.0, Vec3.new(0.3, 0.8, 0.8), 0.2), Sphere.new(Vec3.new(-5.0, 0.0, -15.0), 2.0, Vec3.new(0.3, 0.5, 0.8), 0.2), Sphere.new(Vec3.new(-2.0, -1.0, -10.0), 1.0, Vec3.new(0.1, 0.1, 0.1), 0.1, 0.8), ], [ Light.new(Vec3.new(-10.0, 20.0, 30.0), Vec3.new(2.0, 2.0, 2.0)), ] ) SDL.init SDL.hide_cursor surface = SDL.set_video_mode WIDTH, HEIGHT, 32, LibSDL::DOUBLEBUF | LibSDL::HWSURFACE | LibSDL::ASYNCBLIT first = true begin while true SDL.poll_events do |event| if event.type.in?(LibSDL::QUIT, LibSDL::KEYDOWN) SDL.quit exit end end if first start = SDL.ticks render scene, surface ms = SDL.ticks - start puts "Rendered in #{ms} ms" first = false end end ensure SDL.quit end ================================================ FILE: samples/sdl/sdl/lib_sdl.cr ================================================ {% if flag?(:darwin) %} @[Link("SDL")] @[Link("SDLMain")] @[Link(framework: "Cocoa")] {% else %} @[Link("SDL")] {% end %} lib LibSDL INIT_TIMER = 0x00000001_u32 INIT_AUDIO = 0x00000010_u32 INIT_VIDEO = 0x00000020_u32 INIT_CDROM = 0x00000100_u32 INIT_JOYSTICK = 0x00000200_u32 INIT_NOPARACHUTE = 0x00100000_u32 INIT_EVENTTHREAD = 0x01000000_u32 INIT_EVERYTHING = 0x0000FFFF_u32 SWSURFACE = 0x00000000_u32 HWSURFACE = 0x00000001_u32 ASYNCBLIT = 0x00000004_u32 ANYFORMAT = 0x10000000_u32 HWPALETTE = 0x20000000_u32 DOUBLEBUF = 0x40000000_u32 FULLSCREEN = 0x80000000_u32 OPENGL = 0x00000002_u32 OPENGLBLIT = 0x0000000A_u32 RESIZABLE = 0x00000010_u32 NOFRAME = 0x00000020_u32 NOEVENT = 0_u8 ACTIVEEVENT = 1_u8 KEYDOWN = 2_u8 KEYUP = 3_u8 MOUSEMOTION = 4_u8 MOUSEBUTTONDOWN = 5_u8 MOUSEBUTTONUP = 6_u8 JOYAXISMOTION = 7_u8 JOYBALLMOTION = 8_u8 JOYHATMOTION = 9_u8 JOYBUTTONDOWN = 10_u8 JOYBUTTONUP = 11_u8 QUIT = 12_u8 SYSWMEVENT = 13_u8 EVENT_RESERVEDA = 14_u8 EVENT_RESERVEDB = 15_u8 VIDEORESIZE = 16_u8 VIDEOEXPOSE = 17_u8 EVENT_RESERVED2 = 18_u8 EVENT_RESERVED3 = 19_u8 EVENT_RESERVED4 = 20_u8 EVENT_RESERVED5 = 21_u8 EVENT_RESERVED6 = 22_u8 EVENT_RESERVED7 = 23_u8 USEREVENT = 24_u8 NUMEVENTS = 32_u8 HWACCEL = 0x00000100_u32 SRCCOLORKEY = 0x00001000_u32 RLEACCELOK = 0x00002000_u32 RLEACCEL = 0x00004000_u32 SRCALPHA = 0x00010000_u32 PREALLOC = 0x01000000_u32 DISABLE = 0 ENABLE = 1 struct Color r, g, b, unused : UInt8 end struct Rect x, y : Int16 w, h : UInt16 end struct Surface flags : UInt32 format : Void* # TODO w, h : Int32 pitch : UInt16 pixels : Void* # TODO end enum Key ESCAPE = 27 A = 97 B = 98 C = 99 D = 100 E = 101 F = 102 G = 103 H = 104 I = 105 J = 106 K = 107 L = 108 M = 109 N = 110 O = 111 P = 112 Q = 113 R = 114 S = 115 T = 116 U = 117 V = 118 W = 119 X = 120 Y = 121 Z = 122 UP = 273 DOWN = 274 RIGHT = 275 LEFT = 276 end struct KeySym scan_code : UInt8 sym : Key # TODO end struct KeyboardEvent type : UInt8 which : UInt8 state : UInt8 key_sym : KeySym end union Event type : UInt8 key : KeyboardEvent end fun init = SDL_Init(flags : UInt32) : Int32 fun get_error = SDL_GetError : UInt8* fun quit = SDL_Quit : Void fun set_video_mode = SDL_SetVideoMode(width : Int32, height : Int32, bpp : Int32, flags : UInt32) : Surface* fun delay = SDL_Delay(ms : UInt32) : Void fun poll_event = SDL_PollEvent(event : Event*) : Int32 fun wait_event = SDL_WaitEvent(event : Event*) : Int32 fun lock_surface = SDL_LockSurface(surface : Surface*) : Int32 fun unlock_surface = SDL_UnlockSurface(surface : Surface*) : Void fun update_rect = SDL_UpdateRect(screen : Surface*, x : Int32, y : Int32, w : Int32, h : Int32) : Void fun show_cursor = SDL_ShowCursor(toggle : Int32) : Int32 fun get_ticks = SDL_GetTicks : UInt32 fun flip = SDL_Flip(screen : Surface*) : Int32 end ================================================ FILE: samples/sdl/sdl/sdl.cr ================================================ require "./*" module SDL def self.init(flags = LibSDL::INIT_EVERYTHING) if LibSDL.init(flags) != 0 raise "Can't initialize SDL: #{error}" end end def self.set_video_mode(width, height, bpp, flags) surface = LibSDL.set_video_mode(width, height, bpp, flags) if surface.null? raise "Can't set SDL video mode: #{error}" end Surface.new(surface, width, height, bpp) end def self.show_cursor LibSDL.show_cursor LibSDL::ENABLE end def self.hide_cursor LibSDL.show_cursor LibSDL::DISABLE end def self.error String.new LibSDL.get_error end def self.ticks LibSDL.get_ticks end def self.quit LibSDL.quit end def self.poll_events(&) while LibSDL.poll_event(out event) == 1 yield event end end end ================================================ FILE: samples/sdl/sdl/surface.cr ================================================ class SDL::Surface getter :surface getter :width getter :height getter :bpp def initialize(@surface : LibSDL::Surface*, @width : Int32, @height : Int32, @bpp : Int32) end def lock LibSDL.lock_surface @surface end def unlock LibSDL.unlock_surface @surface end def update_rect(x, y, w, h) LibSDL.update_rect @surface, x, y, w, h end def flip LibSDL.flip @surface end def []=(offset, color) (@surface.value.pixels.as(UInt32*))[offset] = color.to_u32! end def []=(x, y, color) self[y.to_i32 * @width + x.to_i32] = color end def offset(x, y) x.to_i32 + (y.to_i32 * @width) end end ================================================ FILE: samples/sdl/tv.cr ================================================ require "./sdl/sdl" class ColorMaker enum State BlueUp BlueDown GreenUp GreenDown RedUp RedDown end @state : State def initialize(@delay : Int32) @r = 0 @g = 255 @b = 0 @time = 0 @state = :blue_up end def next @time += 1 if @time == @delay next_state @time = 0 end end def next_state case @state when .green_up? @g += 1 @state = :red_down if @g == 255 when .red_down? @r -= 1 @state = :blue_up if @r == 0 when .blue_up? @b += 1 @state = :green_down if @b == 255 when .green_down? @g -= 1 @state = :red_up if @g == 0 when .red_up? @r += 1 @state = :blue_down if @r == 255 when .blue_down? @b -= 1 @state = :green_up if @b == 0 end end def black_color make_alpha_color(0.25) end def dark_color make_alpha_color(0.5) end def light_color make_alpha_color(1.0) end def make_alpha_color(multiplier) rand = Random.next_int r = ((rand >> 16) % 256).to_i g = ((rand >> 8) % 256).to_i b = (rand % 256).to_i r = saturate_color(r, @r, multiplier) g = saturate_color(g, @g, multiplier) b = saturate_color(b, @b, multiplier) make_color r, g, b, 0 end def saturate_color(random, component, multiplier) Math.min(random, (component * multiplier).to_i) end def make_color(r, g, b, a) (b << 24) + (g << 16) + (r << 8) + a end end class Rectangle def initialize(@x : Int32, @y : Int32, @light : Bool) end def light? @light end def contains?(x, y) @x == x && @y == y end end def parse_rectangles rects = [] of Rectangle lines = File.read("#{__DIR__}/tv.txt").split('\n').map(&.rstrip) lines.each_with_index do |line, y| x = 0 line.each_char do |c| if c == 'x' rects << Rectangle.new(x, y, true) elsif c == '.' rects << Rectangle.new(x, y, false) end x += 1 end end rects end width = 640 height = 480 delay = ARGV.size > 1 ? ARGV[1].to_i : 1 SDL.init SDL.show_cursor surface = SDL.set_video_mode width, height, 32, LibSDL::DOUBLEBUF | LibSDL::HWSURFACE | LibSDL::ASYNCBLIT | LibSDL::FULLSCREEN frames = 0_u32 start = SDL.ticks color_maker = ColorMaker.new(delay) rects = parse_rectangles puts "Rects: #{rects.size}" begin while true SDL.poll_events do |event| if event.type.in?(LibSDL::QUIT, LibSDL::KEYDOWN) ms = SDL.ticks - start puts "#{frames} frames in #{ms} ms" puts "Average FPS: #{frames / (ms * 0.001)}" SDL.quit exit end end surface.lock (height // 10).times do |h| (width // 10).times do |w| rect = rects.find(&.contains?(w, h)) 10.times do |y| 10.times do |x| surface[x + 10 * w, y + 10 * h] = rect ? (rect.light? ? color_maker.light_color : color_maker.dark_color) : color_maker.black_color end end end end color_maker.next surface.unlock surface.flip frames += 1 end ensure SDL.quit end ================================================ FILE: samples/sdl/tv.txt ================================================ xxxxx xxxx x x xxxxx xxxxx xxxxx x x..... x...x x. x. x..... .x... x...x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. xxxx x x . xxxxx x. xxxxx. x. x. x...x x . ...x. x. x...x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. x. xxxxx x. x. x. xxxxx. x. x. x. xxxxx ..... . . . ..... . . . ..... ================================================ FILE: samples/sieve.cr ================================================ # Compute prime numbers up to 100 with the Sieve of Eratosthenes max = 100 sieve = Array.new(max + 1, true) sieve[0] = false sieve[1] = false 2.step(to: Math.sqrt(max)) do |i| if sieve[i] (i * i).step(to: max, by: i) do |j| sieve[j] = false end end end sieve.each_with_index do |prime, number| if prime puts number end end ================================================ FILE: samples/spectral-norm.cr ================================================ # Copied with little modifications from: https://github.com/wmoxam/Ruby-Benchmarks-Game/blob/master/benchmarks/spectral-norm.rb def eval_A(i, j) 1.0_f64 / ((i + j) * (i + j + 1.0) / 2.0 + i + 1.0) end def eval_A_times_u(u) (0...u.size).map do |i| v = 0.0_f64 (0...u.size).each do |j| v += eval_A(i, j) * u[j] end v end end def eval_At_times_u(u) (0...u.size).map do |i| v = 0.0_f64 (0...u.size).each do |j| v += eval_A(j, i) * u[j] end v end end def eval_AtA_times_u(u) eval_At_times_u(eval_A_times_u(u)) end n = (ARGV[0]? || 1000).to_i u = Array.new(n, 1.0_f64) v = Array.new(n, 1.0_f64) 10.times do v = eval_AtA_times_u(u) u = eval_AtA_times_u(v) end vBv = vv = 0.0_f64 (0...n).each do |i| vBv += u[i] * v[i] vv += v[i] * v[i] end puts Math.sqrt(vBv / vv) ================================================ FILE: samples/sudoku.cr ================================================ # Copied with little modifications from: https://github.com/attractivechaos/plb/blob/master/sudoku/sudoku_v1.rb def sd_genmat mr = Array.new(324) { [] of Int32 } mc = Array.new(729) { [] of Int32 } r = 0 (0...9).each do |i| (0...9).each do |j| (0...9).each do |k| mc[r] = [9 * i + j, (i // 3 * 3 + j // 3) * 9 + k + 81, 9 * i + k + 162, 9 * j + k + 243] r += 1 end end end (0...729).each do |r2| (0...4).each do |c2| mr[mc[r2][c2]].push(r2) end end {mr, mc} end def sd_update(mr, mc, sr, sc, r, v) min, min_c = 10, 0 (0...4).each do |c2| if v > 0 sc[mc[r][c2]] += 128 else sc[mc[r][c2]] -= 128 end end (0...4).each do |c2| c = mc[r][c2] if v > 0 (0...9).each do |r2| rr = mr[c][r2] sr[rr] += +1 if sr[rr] == 1 p = mc[rr] sc[p[0]] -= 1; sc[p[1]] -= 1; sc[p[2]] -= 1; sc[p[3]] -= 1 if sc[p[0]] < min min, min_c = sc[p[0]], p[0] end if sc[p[1]] < min min, min_c = sc[p[1]], p[1] end if sc[p[2]] < min min, min_c = sc[p[2]], p[2] end if sc[p[3]] < min min, min_c = sc[p[3]], p[3] end end end else (0...9).each do |r2| rr = mr[c][r2] sr[rr] -= 1 if sr[rr] == 0 p = mc[rr] sc[p[0]] += 1; sc[p[1]] += 1; sc[p[2]] += 1; sc[p[3]] += 1 end end end end {min, min_c} end def sd_solve(mr, mc, s) ret = [] of Array(Int32) sr, sc, hints = Array.new(729, 0), Array.new(324, 9), 0 (0...81).each do |i| a = ('1' <= s[i] <= '9') ? s[i].ord - 49 : -1 if a >= 0 sd_update(mr, mc, sr, sc, i * 9 + a, 1) hints += 1 end end cr, cc = Array.new(81, -1), Array.new(81, 0) i, min, dir = 0, 10, 1 loop do while i >= 0 && i < 81 - hints if dir == 1 if min > 1 (0...324).each do |c| if sc[c] < min min, cc[i] = sc[c], c break if min < 2 end end end if min == 0 || min == 10 cr[i], dir, i = -1, -1, i - 1 end end c = cc[i] if dir == -1 && cr[i] >= 0 sd_update(mr, mc, sr, sc, mr[c][cr[i]], -1) end r2_ = 9 (cr[i] + 1...9).each do |r2| if sr[mr[c][r2]] == 0 r2_ = r2 break end end if r2_ < 9 min, cc[i + 1] = sd_update(mr, mc, sr, sc, mr[c][r2_], 1) cr[i], dir, i = r2_, 1, i + 1 else cr[i], dir, i = -1, -1, i - 1 end end break if i < 0 o = [] of Int32 (0...81).each { |j| o.push((s[j].ord - 49).to_i32) } (0...i).each do |j| r = mr[cc[j]][cr[j]] o[r // 9] = r % 9 + 1 end ret.push(o) i, dir = i - 1, -1 end ret end sudoku = <<-SUDOKU ..............3.85..1.2.......5.7.....4...1...9.......5......73..2.1........4...9 # near worst case for brute-force solver (wiki) .......12........3..23..4....18....5.6..7.8.......9.....85.....9...4.5..47...6... # gsf's sudoku q1 (Platinum Blonde) .2..5.7..4..1....68....3...2....8..3.4..2.5.....6...1...2.9.....9......57.4...9.. # (Cheese) ........3..1..56...9..4..7......9.5.7.......8.5.4.2....8..2..9...35..1..6........ # (Fata Morgana) 12.3....435....1....4........54..2..6...7.........8.9...31..5.......9.7.....6...8 # (Red Dwarf) 1.......2.9.4...5...6...7...5.9.3.......7.......85..4.7.....6...3...9.8...2.....1 # (Easter Monster) .......39.....1..5..3.5.8....8.9...6.7...2...1..4.......9.8..5..2....6..4..7..... # Nicolas Juillerat's Sudoku explainer 1.2.1 (top 5) 12.3.....4.....3....3.5......42..5......8...9.6...5.7...15..2......9..6......7..8 ..3..6.8....1..2......7...4..9..8.6..3..4...1.7.2.....3....5.....5...6..98.....5. 1.......9..67...2..8....4......75.3...5..2....6.3......9....8..6...4...1..25...6. ..9...4...7.3...2.8...6...71..8....6....1..7.....56...3....5..1.4.....9...2...7.. ....9..5..1.....3...23..7....45...7.8.....2.......64...9..1.....8..6......54....7 # dukuso's suexrat9 (top 1) 7.8...3.....2.1...5.........4.....263...8.......1...9..9.6....4....7.5........... 3.7.4...........918........4.....7.....16.......25..........38..9....5...2.6..... ........8..3...4...9..2..6.....79.......612...6.5.2.7...8...5...1.....2.4.5.....3 # dukuso's suexratt (top 1) .......1.4.........2...........5.4.7..8...3....1.9....3..4..2...5.1........8.6... # first 2 from sudoku17 .......12....35......6...7.7.....3.....4..8..1...........12.....8.....4..5....6.. 1.......2.9.4...5...6...7...5.3.4.......6........58.4...2...6...3...9.8.7.......1 .....1.2.3...4.5.....6....7..2.....1.8..9..3.4.....8..5....2....9..3.4....67..... SUDOKU def solve_all(sudoku) mr, mc = sd_genmat() sudoku.split('\n').compact_map do |line| if line.size >= 81 ret = sd_solve(mr, mc, line) ret.map(&.join) end end end 10.times do |i| res = solve_all(sudoku) res.each { |str| puts str[0] } if i == 0 end ================================================ FILE: samples/tcp_client.cr ================================================ require "socket" # goes with tcp_server.cr socket = TCPSocket.new "127.0.0.1", 9000 10.times do |i| socket.puts i puts "Server response: #{socket.gets}" sleep 0.5.seconds end ================================================ FILE: samples/tcp_server.cr ================================================ require "socket" # goes with tcp_client.cr def process(client) client_addr = client.remote_address puts "#{client_addr} connected" while msg = client.read_line puts "#{client_addr} msg '#{msg}'" client.puts msg end rescue IO::EOFError puts "#{client_addr} disconnected" ensure client.close end server = TCPServer.new "127.0.0.1", 9000 puts "Listening on 127.0.0.1:9000" loop { spawn process(server.accept) } ================================================ FILE: samples/text_raytracer.cr ================================================ # Ported from Rust from https://gist.github.com/joshmarinacci/c84d0979e100d107f685 record Vector, x : Float64, y : Float64, z : Float64 do def scale(s) Vector.new(x * s, y * s, z * s) end def +(other) Vector.new(x + other.x, y + other.y, z + other.z) end def -(other) Vector.new(x - other.x, y - other.y, z - other.z) end def dot(other) x*other.x + y*other.y + z*other.z end def magnitude Math.sqrt self.dot(self) end def normalize scale(1.0 / magnitude) end end record Ray, orig : Vector, dir : Vector record Color, r : Float64, g : Float64, b : Float64 do def scale(s) Color.new(r * s, g * s, b * s) end def +(other) Color.new(r + other.r, g + other.g, b + other.b) end end record Sphere, center : Vector, radius : Float64, color : Color do def get_normal(pt) (pt - center).normalize end end record Light, position : Vector, color : Color record Hit, obj : Sphere, value : Float64 WHITE = Color.new(1.0, 1.0, 1.0) RED = Color.new(1.0, 0.0, 0.0) GREEN = Color.new(0.0, 1.0, 0.0) BLUE = Color.new(0.0, 0.0, 1.0) LIGHT1 = Light.new(Vector.new(0.7, -1.0, 1.7), WHITE) def shade_pixel(ray, obj, tval) pi = ray.orig + ray.dir.scale(tval) color = diffuse_shading pi, obj, LIGHT1 col = (color.r + color.g + color.b) / 3.0 (col * 6.0).to_i end def intersect_sphere(ray, center, radius) l = center - ray.orig tca = l.dot(ray.dir) if tca < 0.0 return nil end d2 = l.dot(l) - tca*tca r2 = radius*radius if d2 > r2 return nil end thc = Math.sqrt(r2 - d2) t0 = tca - thc # t1 = tca + thc if t0 > 10_000 return nil end t0 end def clamp(x, a, b) return a if x < a return b if x > b x end def diffuse_shading(pi, obj, light) n = obj.get_normal(pi) lam1 = (light.position - pi).normalize.dot(n) lam2 = clamp lam1, 0.0, 1.0 light.color.scale(lam2*0.5) + obj.color.scale(0.3) end puts "Hello, worlds!" lut = %w(. - + * X M) w = 20 * 4 h = 10 * 4 scene = [ Sphere.new(Vector.new(-1.0, 0.0, 3.0), 0.3, RED), Sphere.new(Vector.new(0.0, 0.0, 3.0), 0.8, GREEN), Sphere.new(Vector.new(1.0, 0.0, 3.0), 0.4, BLUE), ] (0...h).each do |j| puts "--" (0...w).each do |i| fw, fi, fj, fh = w.to_f, i.to_f, j.to_f, h.to_f ray = Ray.new( Vector.new(0.0, 0.0, 0.0), Vector.new((fi - fw/2.0)/fw, (fj - fh/2.0)/fh, 1.0).normalize ) hit = nil scene.each do |obj| ret = intersect_sphere(ray, obj.center, obj.radius) if ret hit = Hit.new obj, ret end end if hit pixel = lut[shade_pixel(ray, hit.obj, hit.value)] else pixel = ' ' end print pixel end end puts "we are done!" ================================================ FILE: samples/tree.cr ================================================ class Node @left : self? @right : self? def initialize(@value : Char) end def add(x) if x < @value if left = @left left.add(x) else @left = Node.new(x) end else if right = @right right.add(x) else @right = Node.new(x) end end end def print @left.try &.print print @value @right.try &.print end end root = Node.new('$') "crystalrocks!".each_char do |c| root.add c end root.print # => !$accklorrssty puts ================================================ FILE: samples/wordcount.cr ================================================ # Ported from http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html require "option_parser" def do_work(in_filenames, output_filename, ignore_case) if in_filenames.empty? in_files = [STDIN] else in_files = in_filenames.map { |name| File.open(name, "r") } end if output_filename out_file = File.open(output_filename, "w") else out_file = STDOUT end counts = Hash(String, Int32).new(0) in_files.each do |in_file| in_file.each_line do |line| line = line.downcase if ignore_case line.scan(/\w+/) do |match| counts[match[0]] += 1 end end end entries = counts.to_a.sort_by! &.[0] entries.each do |(word, count)| out_file.puts "#{count}\t#{word}" end end output_filename = nil ignore_case = false OptionParser.parse do |opts| opts.banner = "Usage: wordcount [OPTIONS] [FILES]" opts.on("-o NAME", "set output filename") do |filename| output_filename = filename end opts.on("-i", "--ignore-case", "ignore case") do ignore_case = true end opts.on("-h", "--help", "print this help menu") do puts opts end end in_filenames = ARGV do_work in_filenames, output_filename, ignore_case ================================================ FILE: scripts/docs-versions.sh ================================================ #! /usr/bin/env sh git tag --list | \ grep -v -E '0\.1?[0-9]\.' | \ grep '^[0-9]' | \ sort -rV | \ awk ' BEGIN { print "{" print " \"versions\": [" printf " {\"name\": \"nightly\", \"url\": \"/api/master/\", \"released\": false}" } { printf ",\n {\"name\": \"" $1 "\", \"url\": \"/api/" $1 "/\"}" } END { print "\n ]" print "}" } ' ================================================ FILE: scripts/generate_data.mk ================================================ ## Run all data generators ## $ make -f scripts/generate_data.mk ## Generate time zone database for stdlib specs ## $ make zoneinfo -f scripts/generate_data.mk TZDB_VERSION := 2025c ifeq ($(OS),Windows_NT) BIN_CRYSTAL=bin\crystal else BIN_CRYSTAL=bin/crystal endif .PHONY: all all: zoneinfo ## Run all generators $(BIN_CRYSTAL) run scripts/generate_grapheme_break_specs.cr $(BIN_CRYSTAL) run scripts/generate_grapheme_properties.cr $(BIN_CRYSTAL) run scripts/generate_ssl_server_defaults.cr $(BIN_CRYSTAL) run scripts/generate_unicode_data.cr $(BIN_CRYSTAL) run scripts/generate_windows_zone_names.cr $(BIN_CRYSTAL) run scripts/generate_html_entities.cr .PHONY: zoneinfo zoneinfo: spec/std/data/zoneinfo.zip ## Generate time zone database for stdlib specs spec/std/data/zoneinfo.zip: wget -O- https://data.iana.org/time-zones/tzdb-latest.tar.lz | tar -x --lzip $(MAKE) -C 'tzdb-$(TZDB_VERSION)' zones REDO=posix_only DESTDIR=stage TZDIR=/ ZFLAGS='-b fat' rm -f spec/std/data/zoneinfo.zip cd 'tzdb-$(TZDB_VERSION)/stage' && zip -0 -r ../../spec/std/data/zoneinfo.zip . .PHONY: help help: ## Show this help @echo @printf '\033[34mtargets:\033[0m\n' @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34moptional variables:\033[0m\n' @grep -hE '^[a-zA-Z_-]+ \?=.*?## .*$$' $(MAKEFILE_LIST) |\ sort |\ awk 'BEGIN {FS = " \\?=.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' @echo @printf '\033[34mrecipes:\033[0m\n' @grep -hE '^##.*$$' $(MAKEFILE_LIST) |\ awk 'BEGIN {FS = "## "}; /^## [a-zA-Z_-]/ {printf " \033[36m%s\033[0m\n", $$2}; /^## / {printf " %s\n", $$2}' ================================================ FILE: scripts/generate_glob_specs.sh ================================================ #!/bin/env bash # This tool generates the tests in spec/std/file/match-fast-glob_spec.cr # from https://github.com/oxc-project/fast-glob/blob/main/tests/test.rs # converted to Crystal set -euo pipefail target=spec/std/file/match-fast-glob_spec.cr URL="https://raw.githubusercontent.com/oxc-project/fast-glob/refs/heads/main/tests/test.rs" curl -L "$URL" | ( echo ' # This file was automatically generated by running: # # scripts/generate_glob_specs.cr # # DO NOT EDIT ' echo " # These tests are autogenerated from $URL # They are are collection of tests from bash and micromatch # https://github.com/micromatch/picomatch/blob/master/test/bash.js. " echo ' require "spec" private def assert_file_matches(pattern, path : String, *, file = __FILE__, line = __LINE__) File.match?(pattern, path).should be_true, file: file, line: line File.match?(pattern, Path.posix(path)).should be_true, file: file, line: line File.match?(pattern, Path.posix(path).to_windows(mappings: false)).should be_true, file: file, line: line end private def refute_file_matches(pattern, path : String, *, file = __FILE__, line = __LINE__) File.match?(pattern, path).should be_false, file: file, line: line File.match?(pattern, Path.posix(path)).should be_false, file: file, line: line File.match?(pattern, Path.posix(path).to_windows(mappings: false)).should be_false, file: file, line: line end ' echo 'describe "File .match? bash tests" do' sed -E '1,5d' | sed '/let patterns/,/#\[test\]/d; s/fn not_paired_braces/end\n\nfn not_paired_braces/' | # drop complex patterns implementation sed '/fn fuzz_tests/,$d' | # drop complex fuzz tests implementation sed '/^\s*#\[/d' | sed -E 's/fn (.*)\(\) \{/it "\1" do/' | sed -E 's/\}$/end/' | sed -E 's|^\s*//|#|' | sed -E 's/assert!\(!glob_match\("(.*)", "(.*)"\)\);/refute_file_matches "\1", "\2"/' | sed -E 's/assert!\(glob_match\("(.*)", "(.*)"\)\);/assert_file_matches "\1", "\2"/' | # multiline assertions: sed -E 's/assert!\(glob_match\(/assert_file_matches(/' | sed -E 's/assert!\(!glob_match\(/refute_file_matches(/' | sed -E 's/\)\);/)/' | sed -E 's/let //' | sed -E 's/it "negation"/pending "negation"/' | # File.match? currently does not support negated patterns sed -E '/it "generic_input"/,/end$/d' # Generic input tests are specific to Rust types echo 'end' ) > "$target" crystal tool format "$target" ================================================ FILE: scripts/generate_grapheme_break_specs.cr ================================================ #! /usr/bin/env crystal # # This script generates the file spec/std/string/graphemes_break_spec.cr # that contains test cases for Unicode grapheme clusters based on the default # Grapheme_Cluster_Break Test # http://www.unicode.org/Public/x.y.z/ucd/auxiliary/GraphemeBreakTest.txt require "http/client" require "../src/compiler/crystal/formatter" UCD_ROOT = "http://www.unicode.org/Public/#{Unicode::VERSION}/ucd/" url = "#{UCD_ROOT}auxiliary/GraphemeBreakTest.txt" path = "#{__DIR__}/../spec/std/string/grapheme_break_spec.cr" def string_or_char(string) if string.size == 1 string[0] else string end end File.open(path, "w") do |file| file.puts <<-CRYSTAL # This file was automatically generated by running: # # scripts/generate_grapheme_break_spec.cr # # See https://www.unicode.org/license.html for the Unicode license agreement. # DO NOT EDIT require "./spec_helper" describe "String#each_grapheme" do CRYSTAL HTTP::Client.get(url).body.each_line do |line| next if line.starts_with?('#') format, _, comment = line.partition('#') # TODO: implement grapheme boundary rule GB9c in UAX29 pending = comment.includes?("[9.3]") graphemes = [] of String | Char string = String.build do |io| grapheme = String::Builder.new format.split.in_groups_of(2) do |ary| operator, codepoint = ary break if codepoint.nil? char = codepoint.to_i(16).chr io << char case operator when "÷" unless grapheme.empty? graphemes << string_or_char(grapheme.to_s) end grapheme = String::Builder.new when "×" else raise "Unexpected operator #{operator.inspect}" end grapheme << char end graphemes << string_or_char(grapheme.to_s) end file.puts " #{%(pending "GB9c" { ) if pending} it_iterates_graphemes #{string.dump}, [#{graphemes.join(", ", &.dump)}] #{" }" if pending} # #{comment}" end file.puts "end" end `crystal tool format #{path}` ================================================ FILE: scripts/generate_grapheme_properties.cr ================================================ #! /usr/bin/env crystal # # This script generates the file src/string/grapheme/properties.cr # that contains compact representations of the GraphemeBreakProperty.txt and emoji-data.txt # file from the unicode specification. require "http/client" require "ecr" record RRange, low : Int32, high : Int32, prop : String UCD_ROOT = "http://www.unicode.org/Public/#{Unicode::VERSION}/ucd/" def shapeup(arr) i = 0 to_del = Array(Int32).new while i < arr.size - 1 if arr[i].high + 1 == arr[i + 1].low low = arr[i].low to_del << i arr.delete_at(i) arr[i] = RRange.new(low, arr[i].high, arr[i].prop) i -= 1 end i += 1 end arr end def parse_graphemes_data(body) result = Hash(String, Array(RRange)).new body.each_line do |line| next unless line = line.strip.presence next if line.starts_with?('#') parts = line.split(';') next unless parts.size >= 2 fields = parts.first.strip.split("..") f1 = fields.first.to_i(16) f2 = fields.size > 1 ? fields[1].to_i(16) : f1 prop = parts[1].split('#').first.strip.gsub('_', "") (result[prop] ||= Array(RRange).new) << RRange.new(f1, f2, prop) end result.transform_values { |v| shapeup(v) } end def parse_emoji(body) emoji = Array(RRange).new body.each_line do |line| next unless line = line.strip.presence next if line.starts_with?('#') next unless line.includes?("; Extended_Pictographic") data = line.split.first.split(';') fields = data.first.split("..") f1 = fields.first.to_i(16) f2 = fields.size > 1 ? fields[1].to_i(16) : f1 next if f2 < 0xFF emoji << RRange.new(f1, f2, "ExtendedPictographic") end shapeup(emoji) end body = HTTP::Client.get("#{UCD_ROOT}auxiliary/GraphemeBreakProperty.txt").body props = parse_graphemes_data(body) body = HTTP::Client.get("#{UCD_ROOT}emoji/emoji-data.txt").body props["ExtendedPictographic"] = parse_emoji(body) props_data = props.values.flatten.sort! { |a, b| a.low <=> b.low } path = "#{__DIR__}/../src/string/grapheme/properties.cr" File.open(path, "w") do |file| ECR.embed "#{__DIR__}/grapheme_properties.ecr", file end `crystal tool format #{path}` ================================================ FILE: scripts/generate_html_entities.cr ================================================ #! /usr/bin/env crystal require "http" require "json" require "ecr" record Entity, characters : String, codepoints : Array(Int32) do include JSON::Serializable include JSON::Serializable::Strict end single_char_entities = [] of {String, Entity} double_char_entities = [] of {String, Entity} HTTP::Client.get("https://html.spec.whatwg.org/entities.json") do |res| Hash(String, Entity).from_json(res.body_io).each do |name, entity| name = name.rchop(';').lchop?('&') || raise "Entity does not begin with &" entities = case entity.codepoints.size when 1; single_char_entities when 2; double_char_entities else raise "Unknown entity codepoint size" end entities << {name, entity} end end single_char_entities.uniq!(&.first).sort_by!(&.first) double_char_entities.uniq!(&.first).sort_by!(&.first) max_entity_name_size = { single_char_entities.max_of { |name, _| name.size }, double_char_entities.max_of { |name, _| name.size }, }.max path = "#{__DIR__}/../src/html/entities.cr" File.open(path, "w") do |file| ECR.embed "#{__DIR__}/html_entities.ecr", file end `crystal tool format #{path}` ================================================ FILE: scripts/generate_llvm_version_info.cr ================================================ #! /usr/bin/env crystal # # This script generates the `lib/llvm_VERSION` file from LLVM-C.dll, needed for # dynamically linking against LLVM on Windows. This is only needed when using an # LLVM installation different from the one bundled with Crystal. require "c/libloaderapi" require "llvm/lib_llvm/config" def find_dll_in_env_path ENV["PATH"]?.try &.split(Process::PATH_DELIMITER, remove_empty: true) do |path| dll_path = File.join(path, "LLVM-C.dll") return dll_path if File.exists?(File.join(path, "LLVM-C.dll")) end end unless dll_fname = ARGV.shift? || find_dll_in_env_path abort "Error: Cannot locate LLVM-C.dll, pass its absolute path as a command-line argument or ensure it is available in the PATH environment variable" end unless dll = LibC.LoadLibraryExW(dll_fname.check_no_null_byte.to_utf16, nil, 0) abort "Error: Failed to load DLL at #{dll_fname}" end begin unless llvm_get_version = LibC.GetProcAddress(dll, "LLVMGetVersion") abort "Error: Failed to resolve LLVMGetVersion" end llvm_get_version = Proc(LibC::UInt*, LibC::UInt*, LibC::UInt*, Nil).new(llvm_get_version, Pointer(Void).null) major = uninitialized LibC::UInt minor = uninitialized LibC::UInt patch = uninitialized LibC::UInt llvm_get_version.call(pointerof(major), pointerof(minor), pointerof(patch)) targets_built = LibLLVM::ALL_TARGETS.select do |target| LibC.GetProcAddress(dll, "LLVMInitialize#{target}Target") && LibC.GetProcAddress(dll, "LLVMInitialize#{target}TargetInfo") end # The list of required system libraries are hardcoded in: # https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/CMakeLists.txt # There is no way to infer them from `dumpbin /dependents` alone, because that # command lists DLLs only, whereas some of these libraries are purely static. system_libs = %w(psapi shell32 ole32 uuid advapi32) # https://github.com/llvm/llvm-project/commit/a5ffabce98a4b2e9d69009fa3e60f2b154100860 system_libs << "ws2_32" if {major, minor, patch} >= {18, 0, 0} # https://github.com/llvm/llvm-project/commit/cb7690af09b95bb944baf1b5a9ffb18f86c12130 system_libs << "ntdll" if {major, minor, patch} >= {19, 0, 0} puts "#{major}.#{minor}.#{patch}" puts targets_built.join(' ') puts system_libs.join(' ', &.+ ".lib") ensure LibC.FreeLibrary(dll) end ================================================ FILE: scripts/generate_object_properties.cr ================================================ #! /usr/bin/env crystal # # This script generates the `src/object/properties.cr` file with the whole set # of `[class_](getter|setter|property)[?!]` macros to avoid duplicating the # implementations. Having an external script avoids the runtime cost of having # macros generating AST calls to other macros that must expanded again. struct Generator def initialize(@file : File, @macro_prefix : String, @method_prefix : String, @var_prefix : String, @doc_prefix : String) end def puts @file.puts end def puts(message) @file.puts(message) end def def_vars def_vars do <<-TEXT {% if block %} #{@var_prefix}{{var_name}} : {{type}}? {% if name.value %} = {{name.value}} {% end %} {% else %} #{@var_prefix}{{name}} {% end %} TEXT end end def def_vars_no_macro_block def_vars { "#{@var_prefix}{{name}}" } end def def_vars(&) <<-TEXT {% if name.is_a?(TypeDeclaration) %} {% var_name = name.var.id %} {% type = name.type %} #{yield.lstrip} {% elsif name.is_a?(Assign) %} {% var_name = name.target %} {% type = nil %} #{@var_prefix}{{name}} {% else %} {% var_name = name.id %} {% type = nil %} {% end %} TEXT end def def_vars! <<-TEXT {% if name.is_a?(TypeDeclaration) %} {% var_name = name.var.id %} {% type = name.type %} #{@var_prefix}{{name}}? {% else %} {% var_name = name.id %} {% type = nil %} {% end %} TEXT end def def_getter(suffix = "") <<-TEXT def #{@method_prefix}{{var_name}}#{suffix} {% if type %} : {{type}} {% end %} {% if block %} if (%value = #{@var_prefix}{{var_name}}).nil? #{@var_prefix}{{var_name}} = {{yield}} else %value end {% else %} #{@var_prefix}{{var_name}} {% end %} end TEXT end def def_getter! <<-TEXT def #{@method_prefix}{{var_name}}? {% if type %} : {{type}}? {% end %} #{@var_prefix}{{var_name}} end def #{@method_prefix}{{var_name}} {% if type %} : {{type}} {% end %} if (%value = #{@var_prefix}{{var_name}}).nil? ::raise ::NilAssertionError.new("{{@type.id}}{{#{@doc_prefix.inspect}.id}}{{var_name}} cannot be nil") else %value end end TEXT end def def_setter <<-TEXT def #{@method_prefix}{{var_name}}=(#{@var_prefix}{{var_name}}{% if type %} : {{type}} {% end %}) end TEXT end def gen_property_macros puts <<-TEXT # Generates both `#{@macro_prefix}getter` and `#{@macro_prefix}setter` # methods to access instance variables. # # Refer to the aforementioned macros for details. macro #{@macro_prefix}property(*names, &block) {% for name in names %} #{def_vars} #{def_getter} #{def_setter} {% end %} end # Generates both `#{@macro_prefix}getter?` and `#{@macro_prefix}setter` # methods to access instance variables. # # Refer to the aforementioned macros for details. macro #{@macro_prefix}property?(*names, &block) {% for name in names %} #{def_vars} #{def_getter "?"} #{def_setter} {% end %} end # Generates both `#{@macro_prefix}getter!` and `#{@macro_prefix}setter` # methods to access instance variables. # # Refer to the aforementioned macros for details. macro #{@macro_prefix}property!(*names) {% for name in names %} #{def_vars!} #{def_getter!} #{def_setter} {% end %} end TEXT end end directory = File.expand_path("../src/object", __DIR__) Dir.mkdir(directory) unless Dir.exists?(directory) output = File.join(directory, "properties.cr") File.open(output, "w") do |f| f.puts "# This file was automatically generated by running:" f.puts "#" f.puts "# scripts/generate_object_properties.cr" f.puts "#" f.puts "# DO NOT EDIT" f.puts f.puts "class Object" g = Generator.new(f, "", "", "@", "#") f.puts <<-TEXT # Defines getter methods to access instance variables. # # Refer to [Getters](#getters) for details. macro getter(*names, &block) {% for name in names %} #{g.def_vars} #{g.def_getter} {% end %} end # Identical to `getter` but defines query methods. # # For example, writing: # # ``` # class Robot # getter? working # end # ``` # # Is equivalent to writing: # # ``` # class Robot # def working? # @working # end # end # ``` # # Refer to [Getters](#getters) for general details. macro getter?(*names, &block) {% for name in names %} #{g.def_vars} #{g.def_getter "?"} {% end %} end # Similar to `getter` but defines both raise-on-nil methods as well as query # methods that return a nilable value. # # If a type is specified, then it will become a nilable type (union of the # type and `Nil`). Unlike the other `getter` methods the value is always # initialized to `nil`. There are no initial value or lazy initialization. # # For example, writing: # # ``` # class Robot # getter! name : String # end # ``` # # Is equivalent to writing: # # ``` # class Robot # @name : String? # # def name? : String? # @name # end # # def name : String # @name.not_nil!("Robot#name cannot be nil") # end # end # ``` # # Refer to [Getters](#getters) for general details. macro getter!(*names) {% for name in names %} #{g.def_vars!} #{g.def_getter!} {% end %} end # Generates setter methods to set instance variables. # # Refer to [Setters](#setters) for general details. macro setter(*names) {% for name in names %} #{g.def_vars_no_macro_block} #{g.def_setter} {% end %} end TEXT g.gen_property_macros g = Generator.new(f, "class_", "self.", "@@", ".") f.puts <<-TEXT # Defines getter methods to access class variables. # # For example, writing: # # ``` # class Robot # class_getter backend # end # ``` # # Is equivalent to writing: # # ``` # class Robot # def self.backend # @@backend # end # end # ``` # # Refer to [Getters](#getters) for details. macro class_getter(*names, &block) {% for name in names %} #{g.def_vars} #{g.def_getter} {% end %} end # Identical to `class_getter` but defines query methods. # # For example, writing: # # ``` # class Robot # class_getter? backend # end # ``` # # Is equivalent to writing: # # ``` # class Robot # def self.backend? # @@backend # end # end # ``` # # Refer to [Getters](#getters) for general details. macro class_getter?(*names, &block) {% for name in names %} #{g.def_vars} #{g.def_getter "?"} {% end %} end # Similar to `class_getter` but defines both raise-on-nil methods as well as # query methods that return a nilable value. # # If a type is specified, then it will become a nilable type (union of the # type and `Nil`). Unlike with `class_getter` the value is always initialized # to `nil`. There are no initial value or lazy initialization. # # For example, writing: # # ``` # class Robot # class_getter! backend : String # end # ``` # # Is equivalent to writing: # # ``` # class Robot # @@backend : String? # # def self.backend? : String? # @@backend # end # # def backend : String # @@backend.not_nil!("Robot.backend cannot be nil") # end # end # ``` # # Refer to [Getters](#getters) for general details. macro class_getter!(*names) {% for name in names %} #{g.def_vars!} #{g.def_getter!} {% end %} end # Generates setter methods to set class variables. # # For example, writing: # # ``` # class Robot # class_setter factories # end # ``` # # Is equivalent to writing: # # ``` # class Robot # @@factories # # def self.factories=(@@factories) # end # end # ``` # # Refer to [Setters](#setters) for general details. macro class_setter(*names) {% for name in names %} #{g.def_vars_no_macro_block} #{g.def_setter} {% end %} end TEXT g.gen_property_macros f.puts "end" end ================================================ FILE: scripts/generate_ssl_server_defaults.cr ================================================ #! /usr/bin/env crystal # # This helper fetches the Mozilla recommendations for default TLS ciphers # (https://wiki.mozilla.org/Security/Server_Side_TLS) and automatically places # them in src/openssl/ssl/defaults.cr require "http" require "json" struct Configuration include JSON::Serializable getter oldest_clients : Array(String) getter ciphersuites : Array(String) @[JSON::Field(root: "openssl")] getter ciphers : Array(String) end struct Guidelines include JSON::Serializable @[JSON::Field(converter: String::RawConverter)] getter version : String getter href : String getter configurations : Hash(String, Configuration) end url = ARGV.shift? || "https://ssl-config.mozilla.org/guidelines/latest.json" DEFAULTS_FILE = File.expand_path("../src/openssl/ssl/defaults.cr", __DIR__) guidelines = Guidelines.from_json(HTTP::Client.get(url).body) disabled_ciphers = %w(!RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS) File.open(DEFAULTS_FILE, "w") do |file| file.puts <<-CRYSTAL # THIS FILE WAS AUTOMATICALLY GENERATED BY scripts/#{File.basename(__FILE__)} # on #{Time.utc}. abstract class OpenSSL::SSL::Context CRYSTAL guidelines.configurations.join(file, '\n') do |(level, configuration)| clients = configuration.oldest_clients ciphersuites = configuration.ciphersuites ciphers = configuration.ciphers all_ciphers = ciphersuites + ciphers + disabled_ciphers file.puts <<-CRYSTAL # The list of secure ciphers on **#{level}** compatibility level as per Mozilla # recommendations. # # The oldest clients supported by this configuration are: # * #{clients.join("\n # * ")} # # This list represents version #{guidelines.version} of the #{level} configuration # available at #{guidelines.href}. # # See https://wiki.mozilla.org/Security/Server_Side_TLS for details. @[Deprecated("Deprecated with no replacement. Prefer setting a security level, global system configuration, or build your own from https://ssl-config.mozilla.org")] CIPHERS_#{level.upcase} = "#{all_ciphers.join(":")}" # The list of secure ciphersuites on **#{level}** compatibility level as per Mozilla # recommendations. # # The oldest clients supported by this configuration are: # * #{clients.join("\n # * ")} # # This list represents version #{guidelines.version} of the #{level} configuration # available at #{guidelines.href}. # # See https://wiki.mozilla.org/Security/Server_Side_TLS for details. @[Deprecated("Deprecated with no replacement. Prefer setting a security level, global system configuration, or build your own from https://ssl-config.mozilla.org")] CIPHER_SUITES_#{level.upcase} = "#{ciphersuites.join(":")}" CRYSTAL end file.puts "end" end ================================================ FILE: scripts/generate_unicode_data.cr ================================================ #! /usr/bin/env crystal # # This script generates the file src/unicode/data.cr # that contains compact representations of the UnicodeData.txt # file from the unicode specification. require "http/client" require "ecr" require "../src/compiler/crystal/formatter" UCD_ROOT = "http://www.unicode.org/Public/#{Unicode::VERSION}/ucd/" enum DecompositionType None Canonical Compatibility end # Each entry in UnicodeData.txt # (some info is missing but we don't use it yet) record Entry, codepoint : Int32, name : String, general_category : String, decomposition_type : DecompositionType, decomposition_mapping : Array(Int32)?, upcase : Int32?, downcase : Int32?, casefold : Int32? record SpecialCase, codepoint : Int32, value : Array(Int32) record CaseRange, low : Int32, high : Int32, delta : Int32 record AlternateRange, low : Int32, high : Int32 record Stride, low : Int32, high : Int32, stride : Int32 record CanonicalCombiningClassRange, low : Int32, high : Int32, ccc : UInt8 record QuickCheckRange, low : Int32, high : Int32, result : Unicode::QuickCheckResult def case_ranges(entries, &block) ranges = [] of CaseRange first_codepoint = nil last_codepoint = nil first_match = nil last_match = nil entries.each do |entry| codepoint = entry.codepoint match = yield entry if match if last_codepoint == codepoint - 1 && last_match == match - 1 # Continue streak else if last_codepoint && last_match ranges << CaseRange.new(first_codepoint.not_nil!, last_codepoint, first_match.not_nil! - first_codepoint.not_nil!) end first_codepoint = codepoint first_match = match end else if last_codepoint && last_match ranges << CaseRange.new(first_codepoint.not_nil!, last_codepoint, first_match.not_nil! - first_codepoint.not_nil!) end end last_codepoint = codepoint last_match = match end ranges end def alternate_ranges(ranges) alternate = [] of AlternateRange first_codepoint = nil last_codepoint = nil ranges.each do |range| codepoint = range.low if last_codepoint == codepoint - 2 # Continue streak else if first_codepoint alternate << new_alternate_range(first_codepoint, last_codepoint) end first_codepoint = codepoint end last_codepoint = codepoint end if first_codepoint alternate << new_alternate_range(first_codepoint, last_codepoint) end alternate end def new_alternate_range(first_codepoint, last_codepoint) # The last codepoint is the one for the uppercase letter and we # need to also consider the next codepoint for the lowercase one. AlternateRange.new(first_codepoint, last_codepoint.not_nil! + 1) end def strides(entries, targets, &) strides = [] of Stride entries = entries.select { |entry| targets.includes?(yield entry) } first_entry = nil last_entry = nil stride = nil entries.each do |entry| if first_entry if last_entry current_stride = entry.codepoint - last_entry.codepoint if current_stride == stride # Continue stride else if first_entry == last_entry stride = current_stride else stride = 1 if first_entry.name.ends_with?("First>") && last_entry.name.ends_with?("Last>") strides << Stride.new(first_entry.codepoint, last_entry.codepoint, stride.not_nil!) first_entry = entry stride = nil end end end else first_entry = entry end last_entry = entry end if first_entry && last_entry if stride stride = 1 if first_entry.name.ends_with?("First>") && last_entry.name.ends_with?("Last>") strides << Stride.new(first_entry.codepoint, last_entry.codepoint, stride) else strides << Stride.new(first_entry.codepoint, last_entry.codepoint, 1) end end strides end entries = [] of Entry special_cases_downcase = [] of SpecialCase special_cases_titlecase = [] of SpecialCase special_cases_upcase = [] of SpecialCase special_cases_casefold = [] of SpecialCase casefold_mapping = Hash(Int32, Int32).new canonical_combining_classes = [] of CanonicalCombiningClassRange full_composition_exclusions = Set(Int32).new quick_checks = Unicode::NormalizationForm.values.to_h { |kind| {kind, Array(QuickCheckRange).new} } url = "#{UCD_ROOT}CaseFolding.txt" body = HTTP::Client.get(url).body body.each_line do |line| line = line.strip next if line.empty? next if line.starts_with?('#') pieces = line.split(';') codepoint = pieces[0].to_i(16) status = pieces[1].strip[0] casefold = pieces[2].split.map(&.to_i(16)) next if status != 'C' && status != 'F' # casefold uses full case folding (C and F) if casefold.size == 1 casefold_mapping[codepoint] = casefold[0] casefold = nil end if casefold while casefold.size < 3 casefold << 0 end special_cases_casefold << SpecialCase.new(codepoint, casefold) end end url = "#{UCD_ROOT}UnicodeData.txt" body = HTTP::Client.get(url).body body.each_line do |line| line = line.strip next if line.empty? pieces = line.split(';') codepoint = pieces[0].to_i(16) name = pieces[1] general_category = pieces[2] # don't read CanonicalCombiningClass here; the derived properties file has # exact ranges decomposition = pieces[5] if decomposition.starts_with?('<') decomposition_mapping = decomposition.partition("> ")[2].split.map(&.to_i(16)) decomposition_type = DecompositionType::Compatibility else decomposition_mapping = decomposition.presence.try &.split.map(&.to_i(16)) decomposition_type = decomposition_mapping.nil? ? DecompositionType::None : DecompositionType::Canonical end upcase = pieces[12].to_i?(16) downcase = pieces[13].to_i?(16) titlecase = pieces[14].to_i?(16) casefold = casefold_mapping[codepoint]? entries << Entry.new( codepoint: codepoint, name: name, general_category: general_category, decomposition_type: decomposition_type, decomposition_mapping: decomposition_mapping, upcase: upcase, downcase: downcase, casefold: casefold, ) if titlecase && titlecase != upcase special_cases_titlecase << SpecialCase.new(codepoint, [titlecase, 0, 0]) end end url = "#{UCD_ROOT}SpecialCasing.txt" body = HTTP::Client.get(url).body body.each_line do |line| line = line.strip next if line.empty? break if line.starts_with?("# Conditional Mappings") next if line.starts_with?('#') pieces = line.split(';') codepoint = pieces[0].to_i(16) downcase = pieces[1].split.map(&.to_i(16)) if downcase.size > 1 while downcase.size < 3 downcase << 0 end special_cases_downcase << SpecialCase.new(codepoint, downcase) end upcase = pieces[3].split.map(&.to_i(16)) if upcase.size > 1 while upcase.size < 3 upcase << 0 end special_cases_upcase << SpecialCase.new(codepoint, upcase) end titlecase = pieces[2].split.map(&.to_i(16)) if titlecase.size > 1 while titlecase.size < 3 titlecase << 0 end special_cases_titlecase << SpecialCase.new(codepoint, titlecase) end end url = "#{UCD_ROOT}extracted/DerivedCombiningClass.txt" body = HTTP::Client.get(url).body body.each_line do |line| line = line.strip if m = line.match(/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s*;\s*(\d+)/) ccc = m[3].to_u8 next if ccc == 0 low = m[1].to_i(16) high = m[2]?.try(&.to_i(16)) || low canonical_combining_classes << CanonicalCombiningClassRange.new(low, high, ccc) end end url = "#{UCD_ROOT}DerivedNormalizationProps.txt" body = HTTP::Client.get(url).body body.each_line do |line| line = line.strip break if line.starts_with?("# Derived Property: Expands_On_NFD") if m = line.match(/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s*;\s*Full_Composition_Exclusion/) low = m[1].to_i(16) high = m[2]?.try(&.to_i(16)) || low (low..high).each { |codepoint| full_composition_exclusions << codepoint } elsif m = line.match(/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s*;\s*(NFC|NFD|NFKC|NFKD)_QC\s*;\s*(N|M)/) low = m[1].to_i(16) high = m[2]?.try(&.to_i(16)) || low quick_check = quick_checks[Unicode::NormalizationForm.parse(m[3])] result = m[4] == "M" ? Unicode::QuickCheckResult::Maybe : Unicode::QuickCheckResult::No quick_check << QuickCheckRange.new(low, high, result) end end downcase_ranges = case_ranges entries, &.downcase downcase_one_ranges, downcase_ranges = downcase_ranges.partition { |r| r.delta == 1 } upcase_ranges = case_ranges entries, &.upcase upcase_ranges.select! { |r| r.delta != -1 } alternate_ranges = alternate_ranges(downcase_one_ranges) special_cases_downcase.sort_by! &.codepoint special_cases_upcase.sort_by! &.codepoint special_cases_titlecase.reject! &.in?(special_cases_upcase) special_cases_titlecase.sort_by! &.codepoint casefold_ranges = case_ranges entries, &.casefold all_strides = {} of String => Array(Stride) categories = %w(Lu Ll Lt Lm Lo Mn Mc Me Nd Nl No Zs Zl Zp Cc Cf Cs Co Cn) categories.each do |category| all_strides[category] = strides entries, category, &.general_category end canonical_combining_classes.sort_by! &.low canonical_decompositions = entries.compact_map do |entry| next unless entry.decomposition_type.canonical? mapping = entry.decomposition_mapping.not_nil! raise "BUG: Mapping longer than 2 codepoints" unless mapping.size <= 2 {entry.codepoint, mapping[0], mapping[1]? || 0} end # Instead of storing the codepoints for each compatibility decomposition as an # individual `Array`, we store all of them in a single `Array` and refer to its # subsequences using index and count. compatibility_decomposition_data = [] of Int32 compatibility_decompositions = entries.compact_map do |entry| next unless entry.decomposition_type.compatibility? mapping = entry.decomposition_mapping.not_nil! # We try to reuse any existing subsequences in the table that match this # entry's decomposition mapping. This reduces the table size by over 40%, # mainly due to singleton decompositions. It can be further optimized by # solving the shortest common superstring problem. index = (0..compatibility_decomposition_data.size - mapping.size).find do |i| (0...mapping.size).all? do |j| mapping[j] == compatibility_decomposition_data[i + j] end end unless index index = compatibility_decomposition_data.size compatibility_decomposition_data.concat(mapping) end {entry.codepoint, index, mapping.size} end canonical_compositions = canonical_decompositions.compact_map do |codepoint, first, second| next if second == 0 || full_composition_exclusions.includes?(codepoint) {(first.to_i64 << 21) | second, codepoint} end quick_checks.each_value &.sort_by! &.low output = ECR.render "#{__DIR__}/unicode_data.ecr" output = Crystal.format(output) File.write("#{__DIR__}/../src/unicode/data.cr", output) ================================================ FILE: scripts/generate_windows_zone_names.cr ================================================ #! /usr/bin/env crystal # # This script generates the file src/crystal/system/win32/zone_names.cr # that contains mappings for windows time zone names based on the values # found in https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml require "http/client" require "xml" require "../src/compiler/crystal/formatter" require "ecr" # CLDR-18479 Update CLDR data to TZDB 2025b. (#4593) WINDOWS_ZONE_NAMES_SOURCE = "https://raw.githubusercontent.com/unicode-org/cldr/f8369ba0795c79f3bac8eb89967eea359f77835e/common/supplemental/windowsZones.xml" TARGET_FILE = File.join(__DIR__, "..", "src", "crystal", "system", "win32", "zone_names.cr") ZONEINFO_ZIP = File.join(__DIR__, "..", "spec", "std", "data", "zoneinfo.zip") response = HTTP::Client.get(WINDOWS_ZONE_NAMES_SOURCE) xml = XML.parse(response.body) nodes = xml.xpath_nodes("/supplementalData/windowsZones/mapTimezones/mapZone") entries = nodes.flat_map do |node| windows_name = node["other"] territory = node["territory"] node["type"].split(' ', remove_empty: true).map do |tzdata_name| {tzdata_name, territory, windows_name} end end.sort! iana_to_windows_items = entries.compact_map do |tzdata_name, territory, windows_name| location = Time::Location.load_from_dir_or_zip(tzdata_name, ZONEINFO_ZIP) next unless location time = Time.local(location).at_beginning_of_year zone1 = time.zone zone2 = (time + 6.months).zone # southern hemisphere if zone1.offset > zone2.offset zone1, zone2 = zone2, zone1 end {tzdata_name, windows_name, zone1.name, zone2.name} end.uniq! windows_to_iana_items = entries.compact_map do |tzdata_name, territory, windows_name| {windows_name, tzdata_name} if territory == "001" end.uniq! source = ECR.render "#{__DIR__}/windows_zone_names.ecr" source = Crystal.format(source) File.write(TARGET_FILE, source) ================================================ FILE: scripts/git/pre-commit ================================================ #! /bin/sh # # This script ensures Crystal code is correctly formatted before committing it. # It won't apply any format changes automatically. # # Only staged files (the ones to be committed) are being processed, but each file is checked # entirely as it is stored on disc, even parts that are not staged. # # To use this script, install it in the local git repository. # # `curl -sL https://github.com/crystal-lang/crystal/raw/master/scripts/git/pre-commit > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit`. # # Alternatively, in the Crystal repo you can directly link it: `ln -s scripts/git/pre-commit .git/hooks`. # # Called by "git commit" with no arguments. The hook should # exit with non-zero status after issuing an appropriate message if # it wants to stop the commit. changed_cr_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$') [ -z "$changed_cr_files" ] && exit 0 if [ -x bin/crystal ]; then # use bin/crystal wrapper when available to run local compiler build # shellcheck disable=SC2086 exec bin/crystal tool format --check $changed_cr_files >&2 else # shellcheck disable=SC2086 exec crystal tool format --check $changed_cr_files >&2 fi ================================================ FILE: scripts/github-changelog.cr ================================================ #! /usr/bin/env crystal # This helper queries merged pull requests for a given milestone from the GitHub API # and creates formatted changelog entries. # # Entries are grouped by topic (based on topic labels) and ordered by merge date. # Some annotations are automatically added based on labels. # # Usage: # # scripts/github-changelog.cr # # Environment variables: # GITHUB_TOKEN: Access token for the GitHub API (required) require "http/client" require "json" abort "Missing GITHUB_TOKEN env variable" unless ENV["GITHUB_TOKEN"]? api_token = ENV["GITHUB_TOKEN"] case ARGV.size when 0 abort "Missing argument" when 1 repository = "crystal-lang/crystal" milestone = ARGV.first when 2 repository = ARGV[0] milestone = ARGV[1] else abort "Too many arguments. Usage:\n #{PROGRAM_NAME} [] " end def query_prs(api_token, repository, milestone : String, cursor : String?) query = <<-GRAPHQL query($milestone: String, $owner: String!, $repository: String!, $cursor: String) { repository(owner: $owner, name: $repository) { milestones(query: $milestone, first: 1) { nodes { closedAt description dueOn title pullRequests(first: 100, after: $cursor) { nodes { number title mergedAt permalink author { login } labels(first: 10) { nodes { name } } } pageInfo { endCursor hasNextPage } } } } } } GRAPHQL owner, _, name = repository.partition("/") variables = { owner: owner, repository: name, milestone: milestone, cursor: cursor, } response = HTTP::Client.post("https://api.github.com/graphql", body: {query: query, variables: variables}.to_json, headers: HTTP::Headers{ "Authorization" => "bearer #{api_token}", } ) unless response.success? abort "GitHub API response: #{response.status}\n#{response.body}" end response end module LabelNameConverter def self.from_json(pull : JSON::PullParser) pull.on_key! "name" do String.new(pull) end end end record Milestone, closed_at : Time?, description : String?, due_on : Time?, title : String, pull_requests : Array(PullRequest) do include JSON::Serializable @[JSON::Field(key: "dueOn")] @due_on : Time? @[JSON::Field(key: "closedAt")] @closed_at : Time? @[JSON::Field(key: "pullRequests", root: "nodes")] @pull_requests : Array(PullRequest) def release_date closed_at || due_on end end record PullRequest, number : Int32, title : String, merged_at : Time?, permalink : String, author : String?, labels : Array(String) do include JSON::Serializable include Comparable(self) @[JSON::Field(key: "mergedAt")] @merged_at : Time? @[JSON::Field(root: "login")] @author : String? @[JSON::Field(root: "nodes", converter: JSON::ArrayConverter(LabelNameConverter))] @labels : Array(String) def link_ref(io) io << "[#" << number << "]" end def <=>(other : self) sort_tuple <=> other.sort_tuple end def sort_tuple { type || "", topic || [] of String, deprecated? ? 0 : 1, merged_at || Time.unix(0), } end def infra_sort_tuple { topic || [] of String, type || "", deprecated? ? 0 : 1, merged_at || Time.unix(0), } end def primary_topic topic.try(&.[0]?) || "other" end def sub_topic topic.try(&.[1..].join(":").presence) end def topic topics.fetch(0) do STDERR.puts "Missing topic for ##{number}" nil end end def topics topics = labels.compact_map { |label| label.lchop?("topic:").try(&.split(/:|\//)) } topics.reject! &.[0].==("multithreading") topics.sort_by! { |parts| topic_priority = case parts[0] when "infrastructure" then 3 when "tools" then 2 when "lang" then 1 else 0 end {-topic_priority, parts[0]} } end def deprecated? labels.includes?("deprecation") end def breaking? labels.includes?("kind:breaking") end def regression? labels.includes?("kind:regression") end def experimental? labels.includes?("experimental") end def feature? labels.includes?("kind:feature") end def fix? labels.includes?("kind:bug") end def chore? labels.includes?("kind:chore") end def refactor? labels.includes?("kind:refactor") end def docs? labels.includes?("kind:docs") end def specs? labels.includes?("kind:specs") end def performance? labels.includes?("performance") end def infra? labels.any?(&.starts_with?("topic:infrastructure")) end def type case when feature? then "feature" when docs? then "docs" when specs? then "specs" when fix? then "fix" when chore? then "chore" when performance? then "performance" when refactor? then "refactor" else nil end end def section case when breaking? then "breaking" when infra? then "infra" else type || "" end end def fixup? md = title.match(/\[fixup #(.\d+)/) || return md[1]?.try(&.to_i) end def clean_title title.sub(/\s*\[Backport [^\]]+\]\s*/, "").sub(/^\[?(?:#{type}|#{sub_topic})(?::|\]:?) /i, "") end def backported? labels.any?(&.starts_with?("backport")) end def backport? title.includes?("[Backport ") end end def query_milestone(api_token, repository, number) cursor = nil milestone = nil while true response = query_prs(api_token, repository, number, cursor) parser = JSON::PullParser.new(response.body) m = parser.on_key! "data" do parser.on_key! "repository" do parser.on_key! "milestones" do parser.on_key! "nodes" do parser.read_begin_array Milestone.new(parser) ensure parser.read_end_array end end end end if milestone milestone.pull_requests.concat m.pull_requests else milestone = m end json = JSON.parse(response.body) page_info = json.dig("data", "repository", "milestones", "nodes", 0, "pullRequests", "pageInfo") break unless page_info["hasNextPage"].as_bool cursor = page_info["endCursor"].as_s end milestone end milestone = query_milestone(api_token, repository, milestone) class ChangelogEntry getter pull_requests : Array(PullRequest) property backported_from : PullRequest? def initialize(pr : PullRequest) @pull_requests = [pr] end def pr pull_requests[0] end def to_s(io : IO) if sub_topic = pr.sub_topic io << "_(" << sub_topic << ")_ " end if pr.labels.includes?("security") io << "**[security]** " end if pr.labels.includes?("breaking-change") io << "**[breaking]** " end if pr.regression? io << "**[regression]** " end if pr.experimental? io << "**[experimental]** " end if pr.deprecated? io << "**[deprecation]** " end io << pr.clean_title io << " (" pull_requests.join(io, ", ") do |pr| pr.link_ref(io) end if backported_from = self.backported_from io << ", backported from " backported_from.link_ref(io) end authors = collect_authors if authors.present? io << ", thanks " authors.join(io, ", ") do |author| io << "@" << author end end io << ")" end def collect_authors authors = [] of String if backported_from = self.backported_from if author = backported_from.author authors << author end end pull_requests.each_with_index do |pr, i| next if backported_from && i.zero? author = pr.author || next authors << author unless authors.includes?(author) end authors end def print_ref_labels(io) pull_requests.each { |pr| print_ref_label(io, pr) } backported_from.try { |pr| print_ref_label(io, pr) } end def print_ref_label(io, pr) pr.link_ref(io) io << ": " << pr.permalink io.puts end end entries = milestone.pull_requests.compact_map do |pr| ChangelogEntry.new(pr) unless pr.fixup? || pr.backported? end milestone.pull_requests.each do |pr| parent_number = pr.fixup? || next parent_entry = entries.find { |entry| entry.pr.number == parent_number } if parent_entry parent_entry.pull_requests << pr else STDERR.puts "Unresolved fixup: ##{parent_number} for: #{pr.title} (##{pr.number})" end end milestone.pull_requests.each do |pr| next unless pr.backported? backport = entries.find { |entry| entry.pr.backport? && entry.pr.clean_title == pr.clean_title } if backport backport.backported_from = pr else STDERR.puts "Unresolved backport: #{pr.clean_title.inspect} (##{pr.number})" end end sections = entries.group_by(&.pr.section) SECTION_TITLES = { "breaking" => "Breaking changes", "feature" => "Features", "fix" => "Bugfixes", "chore" => "Chores", "performance" => "Performance", "refactor" => "Refactor", "docs" => "Documentation", "specs" => "Specs", "infra" => "Infrastructure", "" => "other", } TOPIC_ORDER = %w[lang stdlib compiler tools other] puts "## [#{milestone.title}] (#{milestone.release_date.try(&.to_s("%F")) || "unreleased"})" if description = milestone.description.presence puts puts description end puts puts "[#{milestone.title}]: https://github.com/#{repository}/releases/#{milestone.title}" puts def print_entries(entries) entries.each do |entry| puts "- #{entry}" end puts entries.each(&.print_ref_labels(STDOUT)) end SECTION_TITLES.each do |id, title| entries = sections[id]? || next puts "### #{title}" puts if id == "infra" entries.sort_by!(&.pr.infra_sort_tuple) print_entries entries else topics = entries.group_by(&.pr.primary_topic) topic_titles = topics.keys.sort_by! { |k| TOPIC_ORDER.index(k) || Int32::MAX } topic_titles.each do |topic_title| topic_entries = topics[topic_title]? || next puts "#### #{topic_title}" puts topic_entries.sort_by!(&.pr) print_entries topic_entries end end end ================================================ FILE: scripts/grapheme_properties.ecr ================================================ # This file was automatically generated by running: # # scripts/generate_grapheme_properties.cr # # DO NOT EDIT struct String::Grapheme # :nodoc: # # The Grapheme Cluster Break Property values # http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Break_Property_Values enum Property Start Any <%- props.keys.each do |key| -%> <%= key %> <%- end -%> ExtendedPlusZeroWidth # returns the Unicode property value (see `Codepoints` constants below) # of the given code point def self.from(char : Char) r = char.ord # run a binary search f = 0 t = Grapheme.codepoints.size while t > f mid = (f + t) // 2 cp = Grapheme.codepoints[mid] if r < cp[0] t = mid next end if r > cp[1] f = mid + 1 next end return cp[2] end Property::Any end end # Maps code point ranges to their properties. In the context of this package, # any code point that is not contained may map to `Property::Any`. The code point # ranges in this slice are numerically sorted. # # These ranges were taken from # http://www.unicode.org/Public/<%= Unicode::VERSION %>/ucd/auxiliary/GraphemeBreakProperty.txt # as well as # http://www.unicode.org/Public/<%= Unicode::VERSION %>/ucd/emoji/emoji-data.txt # ("Extended_Pictographic" only). See # https://www.unicode.org/license.html for the Unicode license agreement. @@codepoints : Array(Tuple(Int32, Int32, Property))? # :nodoc: protected def self.codepoints @@codepoints||= begin data = Array(Tuple(Int32, Int32, Property)).new(<%= props_data.size %>) <%- props_data.each do |range| -%> put(data, <%= sprintf("0x%04X", range.low) %>, <%= sprintf("0x%04X", range.high) %>, Property::<%= range.prop %>) <%- end -%> data end end private def self.put(array : Array, *values) : Nil array << values end end ================================================ FILE: scripts/html_entities.ecr ================================================ # This file was automatically generated by running: # # scripts/generate_html_entities.cr # # DO NOT EDIT module HTML # :nodoc: SINGLE_CHAR_ENTITIES = { <%- single_char_entities.each do |name, entity| -%> <%= name.inspect %>.to_slice => '\u{<%= "%06X" % entity.codepoints[0] %>}', <%- end -%> } of Bytes => Char # :nodoc: DOUBLE_CHAR_ENTITIES = { <%- double_char_entities.each do |name, entity| -%> <%= name.inspect %>.to_slice => "\u{<%= "%04X" % entity.codepoints[0] %>}\u{<%= "%04X" % entity.codepoints[1] %>}", <%- end -%> } of Bytes => String # :nodoc: MAX_ENTITY_NAME_SIZE = <%= max_entity_name_size %> end ================================================ FILE: scripts/print_regex_config.cr ================================================ #! /usr/bin/env crystal {% if Regex::Engine.resolve.name == "Regex::PCRE2" %} enum LibPCRE2::BSR : UInt32 UNICODE = 1 ANYCRLF = 2 end @[Flags] enum LibPCRE2::COMPILED_WIDTHS : UInt32 U8 U16 U32 Unused end enum LibPCRE2::NEWLINE : UInt32 CR = 1 LF = 2 CRLF = 3 ANY = 4 ANYCRLF = 5 NUL = 6 end def config(kind : UInt32.class, what) where = uninitialized UInt32 LibPCRE2.config(what, pointerof(where)) where end def config(kind : Bool.class, what) config(UInt32, what) != 0 end def config(kind : String.class, what) len = LibPCRE2.config(what, nil) if len > 0 where = Bytes.new(len - 1) LibPCRE2.config(what, where) ret = String.new(where) end ret.inspect end def config(kind : Enum.class, what) kind.new(config(UInt32, what)) end puts <<-EOS Using PCRE2 #{config(String, LibPCRE2::CONFIG_VERSION)} * PCRE2_CONFIG_BSR: #{config(LibPCRE2::BSR, LibPCRE2::CONFIG_BSR)} * PCRE2_CONFIG_COMPILED_WIDTHS: #{config(LibPCRE2::COMPILED_WIDTHS, LibPCRE2::CONFIG_COMPILED_WIDTHS)} * PCRE2_CONFIG_DEPTHLIMIT: #{config(UInt32, LibPCRE2::CONFIG_DEPTHLIMIT)} * PCRE2_CONFIG_HEAPLIMIT: #{config(UInt32, LibPCRE2::CONFIG_HEAPLIMIT)} * PCRE2_CONFIG_JIT: #{config(Bool, LibPCRE2::CONFIG_JIT)} * PCRE2_CONFIG_JITTARGET: #{config(String, LibPCRE2::CONFIG_JITTARGET)} * PCRE2_CONFIG_LINKSIZE: #{config(UInt32, LibPCRE2::CONFIG_LINKSIZE)} * PCRE2_CONFIG_MATCHLIMIT: #{config(UInt32, LibPCRE2::CONFIG_MATCHLIMIT)} * PCRE2_CONFIG_NEVER_BACKSLASH_C: #{config(Bool, LibPCRE2::CONFIG_NEVER_BACKSLASH_C)} * PCRE2_CONFIG_NEWLINE: #{config(LibPCRE2::NEWLINE, LibPCRE2::CONFIG_NEWLINE)} * PCRE2_CONFIG_PARENSLIMIT: #{config(UInt32, LibPCRE2::CONFIG_PARENSLIMIT)} * PCRE2_CONFIG_UNICODE: #{config(Bool, LibPCRE2::CONFIG_UNICODE)} * PCRE2_CONFIG_UNICODE_VERSION: #{config(String, LibPCRE2::CONFIG_UNICODE_VERSION)} EOS {% else %} enum LibPCRE::BSR : LibC::Int UNICODE = 0 ANYCRLF = 1 end enum LibPCRE::NEWLINE : LibC::Int CR = 0x000d LF = 0x000a CRLF = 0x0d0a ANYCRLF = -2 ANY = -1 end lib LibPCRE CONFIG_UTF8 = 0 CONFIG_NEWLINE = 1 CONFIG_LINK_SIZE = 2 CONFIG_POSIX_MALLOC_THRESHOLD = 3 CONFIG_MATCH_LIMIT = 4 CONFIG_STACKRECURSE = 5 CONFIG_UNICODE_PROPERTIES = 6 CONFIG_MATCH_LIMIT_RECURSION = 7 CONFIG_BSR = 8 CONFIG_UTF16 = 10 CONFIG_JITTARGET = 11 CONFIG_UTF32 = 12 CONFIG_PARENS_LIMIT = 13 end def config(kind : LibC::Int.class, what) where = uninitialized LibC::Int LibPCRE.config(what, pointerof(where)) where end def config(kind : LibC::ULong.class, what) where = uninitialized LibC::ULong LibPCRE.config(what, pointerof(where)) where end def config(kind : Bool.class, what) config(LibC::Int, what) != 0 end def config(kind : String.class, what) where = uninitialized LibC::Char* LibPCRE.config(what, pointerof(where)) (where ? String.new(where) : nil).inspect end def config(kind : Enum.class, what) kind.new(config(LibC::Int, what)) end puts <<-EOS Using PCRE #{String.new(LibPCRE.version).inspect} * PCRE_CONFIG_BSR: #{config(LibPCRE::BSR, LibPCRE::CONFIG_BSR)} * PCRE_CONFIG_JIT: #{config(Bool, LibPCRE::CONFIG_JIT)} * PCRE_CONFIG_JITTARGET: #{config(String, LibPCRE::CONFIG_JITTARGET)} * PCRE_CONFIG_LINK_SIZE: #{config(LibC::Int, LibPCRE::CONFIG_LINK_SIZE)} * PCRE_CONFIG_PARENS_LIMIT: #{config(LibC::ULong, LibPCRE::CONFIG_PARENS_LIMIT)} * PCRE_CONFIG_MATCH_LIMIT: #{config(LibC::ULong, LibPCRE::CONFIG_MATCH_LIMIT)} * PCRE_CONFIG_MATCH_LIMIT_RECURSION: #{config(LibC::ULong, LibPCRE::CONFIG_MATCH_LIMIT_RECURSION)} * PCRE_CONFIG_NEWLINE: #{config(LibPCRE::NEWLINE, LibPCRE::CONFIG_NEWLINE)} * PCRE_CONFIG_POSIX_MALLOC_THRESHOLD: #{config(LibC::Int, LibPCRE::CONFIG_POSIX_MALLOC_THRESHOLD)} * PCRE_CONFIG_STACKRECURSE: #{config(Bool, LibPCRE::CONFIG_STACKRECURSE)} * PCRE_CONFIG_UTF16: #{config(Bool, LibPCRE::CONFIG_UTF16)} * PCRE_CONFIG_UTF32: #{config(Bool, LibPCRE::CONFIG_UTF32)} * PCRE_CONFIG_UTF8: #{config(Bool, LibPCRE::CONFIG_UTF8)} * PCRE_CONFIG_UNICODE_PROPERTIES: #{config(Bool, LibPCRE::CONFIG_UNICODE_PROPERTIES)} EOS {% end %} ================================================ FILE: scripts/release-update.sh ================================================ #!/usr/bin/env sh # # This helper updates all references to the previous Crystal release as bootstrap version with a new release. # # Usage: # # scripts/release-update.sh 1.3.0 # # See Crystal release checklist: https://github.com/crystal-lang/distribution-scripts/blob/master/processes/crystal-release.md#post-release set -eu CRYSTAL_VERSION=$1 # Write dev version for next minor release into src/VERSION minor_branch="${CRYSTAL_VERSION%.*}" next_minor="$((${minor_branch#*.} + 1))" echo "${CRYSTAL_VERSION%%.*}.${next_minor}.0-dev" > src/VERSION # Update shard.yml sed -i -E "s/version: .*/version: $(cat src/VERSION)/" shard.yml # Remove SOURCE_DATE_EPOCH (only used in source tree of a release) rm -f src/SOURCE_DATE_EPOCH # Edit PREVIOUS_CRYSTAL_BASE_URL in .circleci/config.yml sed -i -E "s|[0-9.]+/crystal-[0-9.]+-[0-9]|$CRYSTAL_VERSION/crystal-$CRYSTAL_VERSION-1|g" .circleci/config.yml # Edit DOCKER_TEST_PREFIX in bin/ci sed -i -E "s|crystallang/crystal:[0-9.]+|crystallang/crystal:$CRYSTAL_VERSION|" bin/ci # Edit prepare_build on_osx download package and folder sed -i -E "s|[0-9.]+/crystal-[0-9.]+-[0-9]|$CRYSTAL_VERSION/crystal-$CRYSTAL_VERSION-1|g" bin/ci sed -i -E "s|crystal-[0-9.]+-[0-9]|crystal-$CRYSTAL_VERSION-1|g" bin/ci # Edit .github/workflows/*.yml to point to docker image # Update the patch version of the latest entry if same minor version to have only one item per minor version previous_release=$(grep -o -P '(?<=crystal_bootstrap_version: ).*(?= # LATEST RELEASE)' .github/workflows/linux.yml) sed -i -E "s/crystal_bootstrap_version: .+ # LATEST RELEASE/crystal_bootstrap_version: $CRYSTAL_VERSION # LATEST RELEASE/" .github/workflows/linux.yml if [ "${minor_branch}" != "${previous_release%.*}" ]; then sed -i -E "/crystal_bootstrap_version:/ s/(, ${previous_release%.*}\.[0-9]*)?\]\$/, $previous_release]/" .github/workflows/forward-compatibility.yml fi sed -i -E "s|crystallang/crystal:[0-9.]+|crystallang/crystal:$CRYSTAL_VERSION|g" .github/workflows/*.yml # Edit .github/workflows/*.yml to update version for install-crystal action sed -i -E "s|crystal: \"[0-9.]+\"|crystal: \"$CRYSTAL_VERSION\"|g" .github/workflows/*.yml # Edit shell.nix latestCrystalBinary using nix-prefetch-url --unpack darwin_url="https://github.com/crystal-lang/crystal/releases/download/$CRYSTAL_VERSION/crystal-$CRYSTAL_VERSION-1-darwin-universal.tar.gz" darwin_sha=$(nix-prefetch-url --unpack "$darwin_url") sed -i -E "s|https://github.com/crystal-lang/crystal/releases/download/[0-9.]+/crystal-[0-9.]+-[0-9]-darwin-universal.tar.gz|$darwin_url|" shell.nix sed -i -E "/darwin-universal\.tar\.gz/ {n;s|sha256:[^\"]+|sha256:$darwin_sha|}" shell.nix linux_url="https://github.com/crystal-lang/crystal/releases/download/$CRYSTAL_VERSION/crystal-$CRYSTAL_VERSION-1-linux-x86_64.tar.gz" linux_sha=$(nix-prefetch-url --unpack "$linux_url") sed -i -E "s|https://github.com/crystal-lang/crystal/releases/download/[0-9.]+/crystal-[0-9.]+-[0-9]-linux-x86_64.tar.gz|$linux_url|" shell.nix sed -i -E "/linux-x86_64\.tar\.gz/ {n;s|sha256:[^\"]+|sha256:$linux_sha|}" shell.nix ================================================ FILE: scripts/test_ssl_server.cr ================================================ #! /usr/bin/env crystal # # This helper runs a default `HTTP::Server` instance and checks its behaviour # using [testssl.sh](https://testssl.sh/). # testssl.sh is a tool for validating TLS implementations. require "http" require "../spec/support/ssl" # This is needed for the ssl_context_pair helper def datapath(*components) File.join("spec", "std", "data", *components) end server = HTTP::Server.new do |context| context.response.content_type = "text/plain" context.response.print "Hello world!" end server_context, _client_context = ssl_context_pair address = server.bind_tls "0.0.0.0", 0, server_context puts "== Starting HTTP server at #{address}" spawn do puts "== Running testssl.sh" puts "This may take some time..." Process.run("testssl.sh", %w(--parallel --nodns none --color 2) << address.to_s, output: :inherit, error: :inherit) server.close end server.listen ================================================ FILE: scripts/unicode_data.ecr ================================================ # This file was automatically generated by running: # # scripts/generate_unicode_data.cr # # DO NOT EDIT module Unicode # Most case conversions map a range to another range. # Here we store: {from, to, delta} private class_getter upcase_ranges : Array({Int32, Int32, Int32}) do data = Array({Int32, Int32, Int32}).new(<%= upcase_ranges.size %>) <%- upcase_ranges.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, <%= range.delta %>) <%- end -%> data end # Most case conversions map a range to another range. # Here we store: {from, to, delta} private class_getter downcase_ranges : Array({Int32, Int32, Int32}) do data = Array({Int32, Int32, Int32}).new(<%= downcase_ranges.size %>) <%- downcase_ranges.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, <%= range.delta %>) <%- end -%> data end # Other case conversions run in an alternated range # of uppercase/lowercase transformations # Here we store {from, to} private class_getter alternate_ranges : Array({Int32, Int32}) do data = Array({Int32, Int32}).new(<%= alternate_ranges.size %>) <%- alternate_ranges.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>) <%- end -%> data end # We store categories as consecutive strides {from, to, stride} # # For example, in this case: # # {1, 10, 1} # {11, 15, 2} # # The values are: 1..10, 11, 13, 15 <%- all_strides.each do |category, strides| -%> private class_getter category_<%= category %> : Array({Int32, Int32, Int32}) do data = Array({Int32, Int32, Int32}).new(<%= strides.size %>) <%- strides.each do |stride| -%> put(data, <%= stride.low %>, <%= stride.high %>, <%= stride.stride %>) <%- end -%> data end <%- end %> # Most casefold conversions map a range to another range. # Here we store: {from, to, delta} private class_getter casefold_ranges : Array({Int32, Int32, Int32}) do data = Array({Int32, Int32, Int32}).new(<%= casefold_ranges.size %>) <%- casefold_ranges.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, <%= range.delta %>) <%- end -%> data end # Special downcase transformation that involve mapping a codepoint # to multiple codepoints. The maximum transformation is always 3 # codepoints, so we store them all as 3 codepoints and 0 means end. private class_getter special_cases_downcase : Hash(Int32, {Int32, Int32, Int32}) do data = Hash(Int32, {Int32, Int32, Int32}).new(initial_capacity: <%= special_cases_downcase.size %>) <%- special_cases_downcase.each do |a_case| -%> put(data, <%= a_case.codepoint %>, <%= a_case.value.join(", ") %>) <%- end %> data end # Special upcase transformation that involve mapping a codepoint # to multiple codepoints. The maximum transformation is always 3 # codepoints, so we store them all as 3 codepoints and 0 means end. private class_getter special_cases_upcase : Hash(Int32, {Int32, Int32, Int32}) do data = Hash(Int32, {Int32, Int32, Int32}).new(initial_capacity: <%= special_cases_upcase.size %>) <%- special_cases_upcase.each do |a_case| -%> put(data, <%= a_case.codepoint %>, <%= a_case.value.join(", ") %>) <%- end %> data end # Titlecase transformation that differs from the uppercase transformation. # The maximum transformation is always 3 codepoints, so we store them all as 3 # codepoints and 0 means end. private class_getter special_cases_titlecase : Hash(Int32, {Int32, Int32, Int32}) do data = Hash(Int32, {Int32, Int32, Int32}).new(initial_capacity: <%= special_cases_titlecase.size %>) <%- special_cases_titlecase.each do |a_case| -%> put(data, <%= a_case.codepoint %>, <%= a_case.value.join(", ") %>) <%- end %> data end # Fold case transformation that involve mapping a codepoint # to multiple codepoints. The maximum transformation is always 3 # codepoints, so we store them all as 3 codepoints and 0 means end. private class_getter fold_cases : Hash(Int32, {Int32, Int32, Int32}) do data = Hash(Int32, {Int32, Int32, Int32}).new(initial_capacity: <%= special_cases_casefold.size %>) <%- special_cases_casefold.each do |a_case| -%> put(data, <%= a_case.codepoint %>, <%= a_case.value.join(", ") %>) <%- end -%> data end # Canonical combining classes. Only non-zero entries are stored. Unicode # guarantees that all class values are within `0..254`. # Here we store: {from, to, class} private class_getter canonical_combining_classes : Array({Int32, Int32, UInt8}) do data = Array({Int32, Int32, UInt8}).new(<%= canonical_combining_classes.size %>) <%- canonical_combining_classes.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, <%= range.ccc %>_u8) <%- end -%> data end # Canonical decomposition mappings, excluding Hangul syllables. The maximum # transformation is always 2 codepoints, so we store them all as 2 codepoints # and 0 means end. private class_getter canonical_decompositions : Hash(Int32, {Int32, Int32}) do data = Hash(Int32, {Int32, Int32}).new(initial_capacity: <%= canonical_decompositions.size %>) <%- canonical_decompositions.each do |decomp| -%> put(data, <%= decomp.join(", ") %>) <%- end -%> data end # Codepoints for compatibility decomposition mappings. private class_getter compatibility_decomposition_data : Array(Int32) do data = Array(Int32).new(<%= compatibility_decomposition_data.size %>) <%- compatibility_decomposition_data.each do |codepoint| -%> put(data, <%= codepoint %>) <%- end -%> data end # Compatibility decomposition mappings, represented as subsequences of # `compatibility_decomposition_data`. The maximum transformation is 18 # codepoints. # Here we store: codepoint => {index, count} private class_getter compatibility_decompositions : Hash(Int32, {Int32, Int32}) do data = Hash(Int32, {Int32, Int32}).new(initial_capacity: <%= compatibility_decompositions.size %>) <%- compatibility_decompositions.each do |codepoint, index, count| -%> put(data, <%= codepoint %>, <%= index %>, <%= count %>) <%- end -%> data end # Reverse mapping of the canonical decompositions, excluding the full # composition exclusions. # Here we store: (first << 21 | second) => codepoint private class_getter canonical_compositions : Hash(Int64, Int32) do data = Hash(Int64, Int32).new(initial_capacity: <%= canonical_compositions.size %>) <%- canonical_compositions.each do |first_second, codepoint| -%> put(data, <%= first_second %>_i64, <%= codepoint %>) <%- end -%> data end # Used to quickly determine whether a codepoint may appear under Normalization # Form C (yes if absent in this table). # Here we store: {low, high, result (no or maybe)} private class_getter nfc_quick_check : Array({Int32, Int32, QuickCheckResult}) do <%- quick_check = quick_checks[Unicode::NormalizationForm::NFC] -%> data = Array({Int32, Int32, QuickCheckResult}).new(<%= quick_check.size %>) <%- quick_check.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, QuickCheckResult::<%= range.result %>) <%- end -%> data end # Used to quickly determine whether a codepoint may appear under Normalization # Form KC (yes if absent in this table). # Here we store: {low, high, result (no or maybe)} private class_getter nfkc_quick_check : Array({Int32, Int32, QuickCheckResult}) do <%- quick_check = quick_checks[Unicode::NormalizationForm::NFKC] -%> data = Array({Int32, Int32, QuickCheckResult}).new(<%= quick_check.size %>) <%- quick_check.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>, QuickCheckResult::<%= range.result %>) <%- end -%> data end # Used to quickly determine whether a codepoint may appear under Normalization # Form D (yes if absent in this table). There are no "maybe" values; # codepoints contained here may not appear under NFD. # Here we store: {low, high} private class_getter nfd_quick_check : Array({Int32, Int32}) do <%- quick_check = quick_checks[Unicode::NormalizationForm::NFD] -%> data = Array({Int32, Int32}).new(<%= quick_check.size %>) <%- quick_check.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>) <%- end -%> data end # Used to quickly determine whether a codepoint may appear under Normalization # Form KD (yes if absent in this table). There are no "maybe" values; # codepoints contained here may not appear under NFKD. # Here we store: {low, high} private class_getter nfkd_quick_check : Array({Int32, Int32}) do <%- quick_check = quick_checks[Unicode::NormalizationForm::NFKD] -%> data = Array({Int32, Int32}).new(<%= quick_check.size %>) <%- quick_check.each do |range| -%> put(data, <%= range.low %>, <%= range.high %>) <%- end -%> data end # TODO: this is needed to avoid generating lots of allocas # in LLVM, which makes LLVM really slow. The compiler should # try to avoid/reuse temporary allocas. # Explanation: https://github.com/crystal-lang/crystal/issues/4516#issuecomment-306226171 private def self.put(array : Array, value) : Nil array << value end private def self.put(array : Array, *values) : Nil array << values end private def self.put(hash : Hash, key, value) : Nil hash[key] = value end private def self.put(hash : Hash, key, *values) : Nil hash[key] = values end end ================================================ FILE: scripts/update-changelog.sh ================================================ #! /bin/sh # This script automates generating changelog with `scripts/github-changelog.cr`, # editing it into `doc/changelog/v${VERSION%.*}.md` and pushing it to a # `changelog/$VERSION` branch. # # It reads the current (dev-)version from `src/VERSION` and generates the # changelog entries for all PRs from the respective GitHub milestone via # `scripts/github-changelog.cr`. # The section is then inserted into the changelog file, overwriting any previous # content for this milestone. # Finally, the changes are committed and pushed to `changelog/$VERSION`. # If the changelog section is *new*, also creates a draft PR for this branch. # # Usage: # # scripts/update-changelog.sh # # Requirements: # # - scripts/github-changelog.cr # - git # - grep # - sed # # Environment variables: # GITHUB_TOKEN: Access token for the GitHub API (required) set -eu VERSION=${1:-$(cat src/VERSION)} VERSION=${VERSION%-dev} base_branch=$(git rev-parse --abbrev-ref HEAD) branch="changelog/$VERSION" current_changelog="CHANGELOG.$VERSION.md" echo "Generating $current_changelog..." scripts/github-changelog.cr "$VERSION" > "$current_changelog" echo "Switching to branch $branch" git switch "$branch" 2>/dev/null || git switch -c "$branch"; # Write release version into src/VERSION echo "${VERSION}" > src/VERSION git add src/VERSION # Update shard.yml sed -i -E "s/version: .*/version: ${VERSION}/" shard.yml git add shard.yml # Write release date into src/SOURCE_DATE_EPOCH release_date=$(head -n1 "$current_changelog" | grep -o -P '(?<=\()[^)]+') date --utc --date="${release_date}" +%s > src/SOURCE_DATE_EPOCH git add src/SOURCE_DATE_EPOCH changelog_path="doc/changelogs/v${VERSION%.*}.md" if [ ! -f "$changelog_path" ]; then echo "Creating new changelog file $changelog_path" printf "# Changelog %s\n\n" "${VERSION%.*}" > "$changelog_path" printf '%s [%s series](./v%s.md)\n' "-" "${VERSION%.*}" "${VERSION%.*}" >> "doc/changelogs/README.md" git add "doc/changelogs/README.md" fi if grep --silent -E "^## \[$VERSION\]" "$changelog_path"; then echo "Replacing section in $changelog_path" sed -i -E "/^## \[$VERSION\]/,/^## /{ /^## \[$VERSION\]/s/.*/cat $current_changelog/e; /^## /!d }" "$changelog_path" git add "$changelog_path" git commit -m "Update changelog for $VERSION" echo git push else echo "Adding new section to $changelog_path" sed -i -E "2r $current_changelog" "$changelog_path" git add "$changelog_path" git commit -m "Add changelog for $VERSION" echo git push -u upstream "$branch" echo gh pr create --draft --base "$base_branch" \ --body "Preview: https://github.com/crystal-lang/crystal/blob/$branch/$changelog_path.md" \ --label "topic:infrastructure" -t "Changelog for $VERSION" --milestone "$VERSION" fi ================================================ FILE: scripts/update-distribution-scripts.sh ================================================ #!/usr/bin/env sh # # This helper updates the reference of [distribution-scripts](https://github.com/crystal-lang/distribution-scripts), # pushes the change to GitHub and creates a pull request. # # Usage: # # scripts/update-distribution_scripts.sh [REF [BRANCH]] # # Parameters: # * REF: Git commit SHA in distribution-scripts (default: HEAD) # * BRANCH: Branch name for CI branch in crystal (default: ci/update-distribution-scripts) # # Requirements: # * packages: git gh sed # * Working directory should be in a checked out work tree of `crystal-lang/crystal`. # # * The default value for reference is the current HEAD of https://github.com/crystal-lang/distribution-scripts. set -eu DISTRIBUTION_SCRIPTS_WORK_DIR=${DISTRIBUTION_SCRIPTS_WORK_DIR:-../distribution-scripts/.git} GIT_DS="git --git-dir=$DISTRIBUTION_SCRIPTS_WORK_DIR" $GIT_DS fetch origin master if [ "${1:-"HEAD"}" = "HEAD" ]; then reference=$($GIT_DS rev-list origin/master | head -1) else reference=${1} fi branch="${2:-"ci/update-distribution-scripts"}" git switch -C "$branch" master old_reference=$(sed -n "/distribution-scripts-version:/{n;n;n;p}" .circleci/config.yml | grep -o -P '(?<=default: ")[^"]+') echo "$old_reference".."$reference" sed -i -E "/distribution-scripts-version:/{n;n;n;s/default: \".*\"/default: \"$reference\"/}" .circleci/config.yml git add .circleci/config.yml message="Updates \`distribution-scripts\` dependency to https://github.com/crystal-lang/distribution-scripts/commit/$reference" log=$($GIT_DS log "$old_reference".."$reference" --format="%s" | sed "s/.*(/crystal-lang\/distribution-scripts/;s/^/* /;s/)$//") message=$(printf "%s\n\nThis includes the following changes:\n\n%s" "$message" "$log") git commit -m "Update distribution-scripts" -m "$message" git show git push -u upstream "$branch" # Confirm creating pull request echo "Create pull request for branch $branch? [y/N]" read -r REPLY if [ "$REPLY" = "y" ]; then gh pr create -R crystal-lang/crystal --fill --label "topic:infrastructure" --assignee "@me" fi ================================================ FILE: scripts/update-shards.sh ================================================ #!/usr/bin/env sh # Update shards release. # # Usage: # # scripts/update-shards.sh [] # # This helper script pulls the latest Shards release from GitHub and updates all # references to the shards release in this repository. # # See Crystal release checklist: https://github.com/crystal-lang/distribution-scripts/blob/master/processes/shards-release.md#post-release set -eu SHARDS_VERSION=${1:-} if [ -z "$SHARDS_VERSION" ]; then # fetch latest release from GitHub SHARDS_VERSION=$(gh release view --repo crystal-lang/shards --json tagName --jq .tagName | cut -c 2-) fi # Update shards ref in mingw64 and win-msvc build actions sed -i "/repository: crystal-lang\/shards/{n;s/ref: .*/ref: v${SHARDS_VERSION}/}" .github/workflows/mingw-w64-steps.yml .github/workflows/win_build_portable.yml ================================================ FILE: scripts/windows_zone_names.ecr ================================================ # This file was automatically generated by running: # # scripts/generate_windows_zone_names.cr # # DO NOT EDIT module Crystal::System::Time # These mappings from IANA to Windows time zone names and tzdata abbreviations # are based on # <%= WINDOWS_ZONE_NAMES_SOURCE %> private class_getter iana_to_windows : Hash(String, {String, String, String}) do data = Hash(String, {String, String, String}).new(initial_capacity: <%= iana_to_windows_items.size %>) <%- iana_to_windows_items.each do |tzdata_name, windows_name, zone1, zone2| -%> put(data, <%= tzdata_name.inspect %>, <%= windows_name.inspect %>, <%= zone1.inspect %>, <%= zone2.inspect %>) <%- end -%> data end # These canonical mappings from Windows to IANA time zone names, used for the # local time zone, are based on # <%= WINDOWS_ZONE_NAMES_SOURCE %> private class_getter windows_to_iana : Hash(String, String) do data = Hash(String, String).new(initial_capacity: <%= windows_to_iana_items.size %>) <%- windows_to_iana_items.each do |windows_name, tzdata_name| -%> put(data, <%= windows_name.inspect %>, <%= tzdata_name.inspect %>) <%- end -%> data end # TODO: this is needed to avoid generating lots of allocas # in LLVM, which makes LLVM really slow. The compiler should # try to avoid/reuse temporary allocas. # Explanation: https://github.com/crystal-lang/crystal/issues/4516#issuecomment-306226171 private def self.put(hash : Hash, key, value) : Nil hash[key] = value end private def self.put(hash : Hash, key, *values) : Nil hash[key] = values end end ================================================ FILE: shard.yml ================================================ name: crystal version: 1.20.0-dev authors: - Crystal Core Team description: | The Crystal standard library and compiler. crystal: ">= 1.0" dependencies: markd: github: icyleaf/markd reply: github: I3oris/reply commit: 13f7eba083f138dd063c68b859c8e315f44fb523 sanitize: github: straight-shoota/sanitize commit: 75c141b619c77956e88f557149566cd28876398b license: Apache-2.0 WITH Swift-exception repository: https://github.com/crystal-lang/crystal homepage: https://crystal-lang.org/ documentation: https://crystal-lang.org/docs ================================================ FILE: shell.nix ================================================ # This nix-shell script can be used to get a complete development environment # for the Crystal compiler. # # You can choose which llvm version use and, on Linux, choose to use musl. # # $ nix-shell --pure # $ nix-shell --pure --arg llvm 10 # $ nix-shell --pure --arg llvm 10 --arg musl true # $ nix-shell --pure --arg llvm 9 # $ nix-shell --pure --arg llvm 9 --argstr system i686-linux # ... # $ nix-shell --pure --arg llvm 6 # # If needed, you can use https://app.cachix.org/cache/crystal-ci to avoid building # packages that are not available in Nix directly. This is mostly useful for musl. # # $ nix-env -iA cachix -f https://cachix.org/api/v1/install # $ cachix use crystal-ci # $ nix-shell --pure --arg musl true # {llvm ? 16, musl ? false, system ? builtins.currentSystem}: let nixpkgs = import (builtins.fetchTarball { name = "nixpkgs-23.05"; url = "https://github.com/NixOS/nixpkgs/archive/23.05.tar.gz"; sha256 = "10wn0l08j9lgqcw8177nh2ljrnxdrpri7bp0g7nvrsn9rkawvlbf"; }) { inherit system; }; pkgs = if musl then nixpkgs.pkgsMusl else nixpkgs; llvmPackages = pkgs."llvmPackages_${toString llvm}"; genericBinary = { url, sha256 }: pkgs.stdenv.mkDerivation rec { name = "crystal-binary"; src = builtins.fetchTarball { inherit url sha256; }; # Extract only the compiler binary installPhase = '' mkdir -p $out/bin if [ -f "${src}/embedded/bin/crystal" ]; then # Darwin packages use embedded/bin/crystal cp ${src}/embedded/bin/crystal $out/bin/ elif [ -f "${src}/lib/crystal/bin/crystal" ]; then # Older Linux packages use lib/crystal/bin/crystal cp ${src}/lib/crystal/bin/crystal $out/bin/ elif [ -f "${src}/bin/crystal" ]; then # Linux packages use bin/crystal cp ${src}/bin/crystal $out/bin/ fi ''; }; # Hashes obtained using `nix-prefetch-url --unpack ` latestCrystalBinary = genericBinary ({ x86_64-darwin = { url = "https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1-darwin-universal.tar.gz"; sha256 = "sha256:1w2ph2sz91pddkpc6nxbgpbx4gvml481g2gr1a5325w7hk523d7v"; }; aarch64-darwin = { url = "https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1-darwin-universal.tar.gz"; sha256 = "sha256:1w2ph2sz91pddkpc6nxbgpbx4gvml481g2gr1a5325w7hk523d7v"; }; x86_64-linux = { url = "https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1-linux-x86_64.tar.gz"; sha256 = "sha256:0vh0m9dppjwv0af40sz8y2y7dm1ysrm2z3va1cgn4g9f9p0wnfcq"; }; aarch64-linux = { url = "https://github.com/crystal-lang/crystal/releases/download/1.19.1/crystal-1.19.1-1-linux-aarch64.tar.gz"; sha256 = "sha256:1c4xgwcxanss5scx4aj814qjb7amwbhbrv8izgfvfq73d8b7azng"; }; }.${pkgs.stdenv.system}); boehmgc = pkgs.boehmgc.override { enableLargeConfig = true; }; stdLibDeps = with pkgs; [ boehmgc gmp libevent libiconv libxml2 libyaml openssl pcre2 zlib ] ++ lib.optionals stdenv.isDarwin [ libiconv ]; tools = [ pkgs.hostname pkgs.git llvmPackages.bintools ] ++ pkgs.lib.optional (!llvmPackages.lldb.meta.broken) llvmPackages.lldb; in pkgs.stdenv.mkDerivation rec { name = "crystal-dev"; buildInputs = tools ++ stdLibDeps ++ [ latestCrystalBinary pkgs.pkg-config llvmPackages.libllvm pkgs.libffi ]; LLVM_CONFIG = "${llvmPackages.libllvm.dev}/bin/llvm-config"; MACOSX_DEPLOYMENT_TARGET = "10.11"; } ================================================ FILE: spec/all_spec.cr ================================================ require "./compiler_spec" require "./std_spec" require "./primitives_spec" ================================================ FILE: spec/compiler/codegen/abi/aarch64_spec.cr ================================================ require "spec" require "llvm" require "compiler/crystal/codegen/abi/aarch64" {% if LibLLVM::BUILT_TARGETS.includes?(:aarch64) %} LLVM.init_aarch64 {% end %} private def abi triple = "aarch64-unknown-linux-gnu" target = LLVM::Target.from_triple(triple) machine = target.create_target_machine(triple) machine.enable_global_isel = false Crystal::ABI::AArch64.new(machine) end private def test(msg, &block : Crystal::ABI, LLVM::Context ->) it msg do abi = abi() ctx = LLVM::Context.new block.call(abi, ctx) end end class Crystal::ABI describe AArch64 do {% if LibLLVM::BUILT_TARGETS.includes?(:aarch64) %} describe "align" do test "for integer" do |abi, ctx| abi.align(ctx.int1).should be_a(::Int32) abi.align(ctx.int1).should eq(1) abi.align(ctx.int8).should eq(1) abi.align(ctx.int16).should eq(2) abi.align(ctx.int32).should eq(4) abi.align(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.align(ctx.int8.pointer).should eq(8) end test "for float" do |abi, ctx| abi.align(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.align(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64])).should eq(8) abi.align(ctx.struct([ctx.int8, ctx.int16])).should eq(2) end test "for packed struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(1) end test "for array" do |abi, ctx| abi.align(ctx.int16.array(10)).should eq(2) end end describe "size" do test "for integer" do |abi, ctx| abi.size(ctx.int1).should be_a(::Int32) abi.size(ctx.int1).should eq(1) abi.size(ctx.int8).should eq(1) abi.size(ctx.int16).should eq(2) abi.size(ctx.int32).should eq(4) abi.size(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.size(ctx.int8.pointer).should eq(8) end test "for float" do |abi, ctx| abi.size(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.size(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64])).should eq(16) abi.size(ctx.struct([ctx.int16, ctx.int8])).should eq(4) abi.size(ctx.struct([ctx.int32, ctx.int8, ctx.int8])).should eq(8) end test "for packed struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(12) end test "for array" do |abi, ctx| abi.size(ctx.int16.array(10)).should eq(20) end end describe "abi_info" do test "does with primitives" do |abi, ctx| arg_types = [ctx.int32, ctx.int64] return_type = ctx.int8 info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(2) info.arg_types[0].should eq(ArgType.direct(ctx.int32)) info.arg_types[1].should eq(ArgType.direct(ctx.int64)) info.return_type.should eq(ArgType.direct(ctx.int8)) end test "does with structs less than 64 bits" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.int32)) info.return_type.should eq(ArgType.direct(str, cast: ctx.int32)) end test "does with structs between 64 and 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.int64.array(2))) info.return_type.should eq(ArgType.direct(str, cast: ctx.int64.array(2))) end test "does with structs larger than 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int64, ctx.int8]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, nil)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with homogeneous structs" do |abi, ctx| str = ctx.struct([ctx.float, ctx.float, ctx.float, ctx.float]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, ctx.float.array(4))) info.return_type.should eq(ArgType.direct(str, ctx.float.array(4))) end end {% end %} end end ================================================ FILE: spec/compiler/codegen/abi/arm_spec.cr ================================================ require "spec" require "llvm" require "compiler/crystal/codegen/abi/arm" {% if LibLLVM::BUILT_TARGETS.includes?(:arm) %} LLVM.init_arm {% end %} private def abi triple = "arm-unknown-linux-gnueabihf" target = LLVM::Target.from_triple(triple) machine = target.create_target_machine(triple) machine.enable_global_isel = false Crystal::ABI::ARM.new(machine) end private def test(msg, &block : Crystal::ABI, LLVM::Context ->) it msg do abi = abi() ctx = LLVM::Context.new block.call(abi, ctx) end end class Crystal::ABI describe ARM do {% if LibLLVM::BUILT_TARGETS.includes?(:arm) %} describe "align" do test "for integer" do |abi, ctx| abi.align(ctx.int1).should be_a(::Int32) abi.align(ctx.int1).should eq(1) abi.align(ctx.int8).should eq(1) abi.align(ctx.int16).should eq(2) abi.align(ctx.int32).should eq(4) abi.align(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.align(ctx.int8.pointer).should eq(4) end test "for float" do |abi, ctx| abi.align(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.align(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64])).should eq(8) abi.align(ctx.struct([ctx.int8, ctx.int16])).should eq(2) end test "for packed struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(1) end test "for array" do |abi, ctx| abi.align(ctx.int16.array(10)).should eq(2) end end describe "size" do test "for integer" do |abi, ctx| abi.size(ctx.int1).should be_a(::Int32) abi.size(ctx.int1).should eq(1) abi.size(ctx.int8).should eq(1) abi.size(ctx.int16).should eq(2) abi.size(ctx.int32).should eq(4) abi.size(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.size(ctx.int8.pointer).should eq(4) end test "for float" do |abi, ctx| abi.size(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.size(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64])).should eq(16) abi.size(ctx.struct([ctx.int16, ctx.int8])).should eq(4) abi.size(ctx.struct([ctx.int32, ctx.int8, ctx.int8])).should eq(8) end test "for packed struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(12) end test "for array" do |abi, ctx| abi.size(ctx.int16.array(10)).should eq(20) end end describe "abi_info" do test "does with primitives" do |abi, ctx| arg_types = [ctx.int32, ctx.int64] return_type = ctx.int8 info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(2) info.arg_types[0].should eq(ArgType.direct(ctx.int32)) info.arg_types[1].should eq(ArgType.direct(ctx.int64)) info.return_type.should eq(ArgType.direct(ctx.int8)) end test "does with structs less than 64 bits" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.int32.array(1))) info.return_type.should eq(ArgType.direct(str, cast: ctx.int32)) end test "does with structs between 64 and 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.int64.array(2))) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with structs larger than 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int64, ctx.int8]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.int64.array(3))) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end end {% end %} end end ================================================ FILE: spec/compiler/codegen/abi/avr_spec.cr ================================================ require "spec" require "llvm" require "compiler/crystal/codegen/abi/avr" {% if LibLLVM::BUILT_TARGETS.includes?(:avr) %} LLVM.init_avr {% end %} private def abi triple = "avr-unknown-unknown-atmega328p" target = LLVM::Target.from_triple(triple) machine = target.create_target_machine(triple) machine.enable_global_isel = false Crystal::ABI::AVR.new(machine) end private def test(msg, &block : Crystal::ABI, LLVM::Context ->) it msg do abi = abi() ctx = LLVM::Context.new block.call(abi, ctx) end end class Crystal::ABI describe AVR do {% if LibLLVM::BUILT_TARGETS.includes?(:avr) %} describe "align" do test "for integer" do |abi, ctx| abi.align(ctx.int1).should be_a(::Int32) abi.align(ctx.int1).should eq(1) abi.align(ctx.int8).should eq(1) abi.align(ctx.int16).should eq(1) abi.align(ctx.int32).should eq(1) abi.align(ctx.int64).should eq(1) end test "for pointer" do |abi, ctx| abi.align(ctx.int8.pointer).should eq(1) end test "for float" do |abi, ctx| abi.align(ctx.float).should eq(1) end test "for double" do |abi, ctx| abi.align(ctx.double).should eq(1) end test "for struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64])).should eq(1) abi.align(ctx.struct([ctx.int8, ctx.int16])).should eq(1) end test "for packed struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(1) end test "for array" do |abi, ctx| abi.align(ctx.int16.array(10)).should eq(1) end end describe "size" do test "for integer" do |abi, ctx| abi.size(ctx.int1).should be_a(::Int32) abi.size(ctx.int1).should eq(1) abi.size(ctx.int8).should eq(1) abi.size(ctx.int16).should eq(2) abi.size(ctx.int32).should eq(4) abi.size(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.size(ctx.int8.pointer).should eq(2) end test "for float" do |abi, ctx| abi.size(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.size(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64])).should eq(12) abi.size(ctx.struct([ctx.int16, ctx.int8])).should eq(3) abi.size(ctx.struct([ctx.int32, ctx.int8, ctx.int8])).should eq(6) end test "for packed struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int8], packed: true)).should eq(5) end test "for array" do |abi, ctx| abi.size(ctx.int16.array(10)).should eq(20) end end describe "abi_info" do {% for bits in [1, 8, 16, 32, 64] %} test "int{{bits}}" do |abi, ctx| arg_type = ArgType.direct(ctx.int{{bits}}) info = abi.abi_info([ctx.int{{bits}}], ctx.int{{bits}}, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(arg_type) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.return_type.should eq(arg_type) info.return_type.kind.should eq(Crystal::ABI::ArgKind::Direct) end {% end %} test "float" do |abi, ctx| arg_type = ArgType.direct(ctx.float) info = abi.abi_info([ctx.float], ctx.float, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(arg_type) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.return_type.should eq(arg_type) info.return_type.kind.should eq(Crystal::ABI::ArgKind::Direct) end test "double" do |abi, ctx| arg_type = ArgType.direct(ctx.double) info = abi.abi_info([ctx.double], ctx.double, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(arg_type) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.return_type.should eq(arg_type) info.return_type.kind.should eq(Crystal::ABI::ArgKind::Direct) end test "multiple arguments" do |abi, ctx| args = Array.new(9) { ctx.int16 } info = abi.abi_info(args, ctx.int8, false, ctx) info.arg_types.size.should eq(9) info.arg_types.each(&.kind.should eq(Crystal::ABI::ArgKind::Direct)) end test "multiple arguments above registers" do |abi, ctx| args = Array.new(5) { ctx.int32 } info = abi.abi_info(args, ctx.int8, false, ctx) info.arg_types.size.should eq(5) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[1].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[2].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[3].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[4].kind.should eq(Crystal::ABI::ArgKind::Indirect) end test "struct args within 18 bytes" do |abi, ctx| args = [ ctx.int8, # rounded to 2 bytes ctx.struct([ctx.int32, ctx.int32]), # 8 bytes ctx.struct([ctx.int32, ctx.int32]), # 8 bytes ] info = abi.abi_info(args, ctx.void, false, ctx) info.arg_types.size.should eq(3) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[1].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[2].kind.should eq(Crystal::ABI::ArgKind::Direct) end test "struct args over 18 bytes" do |abi, ctx| args = [ ctx.int32, # 4 bytes ctx.struct([ctx.int32, ctx.int32]), # 8 bytes ctx.struct([ctx.int32, ctx.int32]), # 8 bytes ] info = abi.abi_info(args, ctx.void, false, ctx) info.arg_types.size.should eq(3) info.arg_types[0].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[1].kind.should eq(Crystal::ABI::ArgKind::Direct) info.arg_types[2].kind.should eq(Crystal::ABI::ArgKind::Indirect) end test "returns struct within 8 bytes" do |abi, ctx| rty = ctx.struct([ctx.int32, ctx.int32]) info = abi.abi_info([] of LLVM::Type, rty, true, ctx) info.return_type.kind.should eq(Crystal::ABI::ArgKind::Direct) end test "returns struct over 8 bytes" do |abi, ctx| rty = ctx.struct([ctx.int32, ctx.int32, ctx.int8]) info = abi.abi_info([] of LLVM::Type, rty, true, ctx) info.return_type.kind.should eq(Crystal::ABI::ArgKind::Indirect) end end {% end %} end end ================================================ FILE: spec/compiler/codegen/abi/x86_64_spec.cr ================================================ require "spec" require "llvm" require "compiler/crystal/codegen/abi/x86_64" require "compiler/crystal/codegen/abi/x86_win64" {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} LLVM.init_x86 {% end %} private def abi(win64 = false) triple = win64 ? "x86_64-windows-msvc" : LLVM.default_target_triple.gsub(/^(.+?)-/, "x86_64-") target = LLVM::Target.from_triple(triple) machine = target.create_target_machine(triple) machine.enable_global_isel = false win64 ? Crystal::ABI::X86_Win64.new(machine) : Crystal::ABI::X86_64.new(machine) end private def test(msg, *, win64 = false, file = __FILE__, line = __LINE__, &block : Crystal::ABI, LLVM::Context ->) it msg, file: file, line: line do abi = abi(win64) ctx = LLVM::Context.new block.call(abi, ctx) end end class Crystal::ABI describe X86_64 do {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} describe "align" do test "for integer" do |abi, ctx| abi.align(ctx.int1).should be_a(::Int32) abi.align(ctx.int1).should eq(1) abi.align(ctx.int8).should eq(1) abi.align(ctx.int16).should eq(2) abi.align(ctx.int32).should eq(4) abi.align(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.align(ctx.int8.pointer).should eq(8) end test "for float" do |abi, ctx| abi.align(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.align(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64])).should eq(8) abi.align(ctx.struct([ctx.int8, ctx.int16])).should eq(2) end test "for packed struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(1) end test "for array" do |abi, ctx| abi.align(ctx.int16.array(10)).should eq(2) end end describe "size" do test "for integer" do |abi, ctx| abi.size(ctx.int1).should be_a(::Int32) abi.size(ctx.int1).should eq(1) abi.size(ctx.int8).should eq(1) abi.size(ctx.int16).should eq(2) abi.size(ctx.int32).should eq(4) abi.size(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.size(ctx.int8.pointer).should eq(8) end test "for float" do |abi, ctx| abi.size(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.size(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64])).should eq(16) abi.size(ctx.struct([ctx.int16, ctx.int8])).should eq(4) abi.size(ctx.struct([ctx.int32, ctx.int8, ctx.int8])).should eq(8) end test "for packed struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(12) end test "for array" do |abi, ctx| abi.size(ctx.int16.array(10)).should eq(20) end end describe "abi_info" do test "does with primitives" do |abi, ctx| arg_types = [ctx.int32, ctx.int64] return_type = ctx.int8 info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(2) info.arg_types[0].should eq(ArgType.direct(ctx.int32)) info.arg_types[1].should eq(ArgType.direct(ctx.int64)) info.return_type.should eq(ArgType.direct(ctx.int8)) end test "does with structs less than 64 bits" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) info.return_type.should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) end test "does with structs between 64 and 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64, ctx.int64]))) info.return_type.should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64, ctx.int64]))) end test "does with structs larger than 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int64, ctx.int8]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with non-packed struct containing packed struct with unaligned fields" do |abi, ctx| inner = ctx.struct([ctx.int16, ctx.int8], packed: true) str = ctx.struct([ctx.int8, inner]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with non-packed struct containing single-element array of packed struct with unaligned fields" do |abi, ctx| inner = ctx.struct([ctx.int16, ctx.int8], packed: true).array(1) str = ctx.struct([ctx.int8, inner]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end end {% end %} end describe X86_Win64 do {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} describe "abi_info" do test "does with structs between 64 and 128 bits", win64: true do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with structs larger than 128 bits", win64: true do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int64, ctx.int8]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with packed struct containing unaligned fields (#9873)" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16], packed: true) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with packed struct not containing unaligned fields" do |abi, ctx| str = ctx.struct([ctx.int16, ctx.int8], packed: true) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) info.return_type.should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) end test "does with array of packed struct containing unaligned fields (#16312)" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16], packed: true).array(1) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) str = ctx.struct([ctx.int8, ctx.int16], packed: true).array(2) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) str = ctx.struct([ctx.int16, ctx.int8], packed: true).array(2) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end test "does with array of packed struct not containing unaligned fields (#16312)" do |abi, ctx| str = ctx.struct([ctx.int16, ctx.int8], packed: true).array(1) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) info.return_type.should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) end end {% end %} end end ================================================ FILE: spec/compiler/codegen/abi/x86_spec.cr ================================================ {% skip_file if flag?(:win32) %} # 32-bit windows is not supported require "spec" require "llvm" require "compiler/crystal/codegen/abi/x86" {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} LLVM.init_x86 {% end %} private def abi triple = {% if flag?(:darwin) %} "i686-unknown-linux-gnu" {% else %} LLVM.default_target_triple.gsub(/^(.+?)-/, "i686-") {% end %} target = LLVM::Target.from_triple(triple) machine = target.create_target_machine(triple) machine.enable_global_isel = false Crystal::ABI::X86.new(machine) end private def test(msg, &block : Crystal::ABI, LLVM::Context ->) it msg do abi = abi() ctx = LLVM::Context.new block.call(abi, ctx) end end class Crystal::ABI describe X86 do {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} describe "align" do test "for integer" do |abi, ctx| abi.align(ctx.int1).should be_a(::Int32) abi.align(ctx.int1).should eq(1) abi.align(ctx.int8).should eq(1) abi.align(ctx.int16).should eq(2) abi.align(ctx.int32).should eq(4) abi.align(ctx.int64).should eq(4) end test "for pointer" do |abi, ctx| abi.align(ctx.int8.pointer).should eq(4) end test "for float" do |abi, ctx| abi.align(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.align(ctx.double).should eq(4) end test "for struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64])).should eq(4) abi.align(ctx.struct([ctx.int8, ctx.int16])).should eq(2) end test "for packed struct" do |abi, ctx| abi.align(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(1) end test "for array" do |abi, ctx| abi.align(ctx.int16.array(10)).should eq(2) end end describe "size" do test "for integer" do |abi, ctx| abi.size(ctx.int1).should be_a(::Int32) abi.size(ctx.int1).should eq(1) abi.size(ctx.int8).should eq(1) abi.size(ctx.int16).should eq(2) abi.size(ctx.int32).should eq(4) abi.size(ctx.int64).should eq(8) end test "for pointer" do |abi, ctx| abi.size(ctx.int8.pointer).should eq(4) end test "for float" do |abi, ctx| abi.size(ctx.float).should eq(4) end test "for double" do |abi, ctx| abi.size(ctx.double).should eq(8) end test "for struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64])).should eq(12) abi.size(ctx.struct([ctx.int16, ctx.int8])).should eq(4) abi.size(ctx.struct([ctx.int32, ctx.int8, ctx.int8])).should eq(8) end test "for packed struct" do |abi, ctx| abi.size(ctx.struct([ctx.int32, ctx.int64], packed: true)).should eq(12) end test "for array" do |abi, ctx| abi.size(ctx.int16.array(10)).should eq(20) end end describe "abi_info" do test "does with primitives" do |abi, ctx| arg_types = [ctx.int32, ctx.int64] return_type = ctx.int8 info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(2) info.arg_types[0].should eq(ArgType.direct(ctx.int32)) info.arg_types[1].should eq(ArgType.direct(ctx.int64)) info.return_type.should eq(ArgType.direct(ctx.int8)) end test "does with structs less than 64 bits" do |abi, ctx| str = ctx.struct([ctx.int8, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, attr: LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, attr: LLVM::Attribute::StructRet)) end test "does with structs between 64 and 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int16]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, attr: LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, attr: LLVM::Attribute::StructRet)) end test "does with structs between 64 and 128 bits" do |abi, ctx| str = ctx.struct([ctx.int64, ctx.int64, ctx.int8]) arg_types = [str] return_type = str info = abi.abi_info(arg_types, return_type, true, ctx) info.arg_types.size.should eq(1) info.arg_types[0].should eq(ArgType.indirect(str, LLVM::Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, LLVM::Attribute::StructRet)) end end {% end %} end end ================================================ FILE: spec/compiler/codegen/alias_spec.cr ================================================ require "../../spec_helper" describe "Code gen: alias" do it "invokes methods on empty array of recursive alias (1)" do run(<<-CRYSTAL).to_string.should eq("") require "prelude" alias Alias = Array(Alias) a = [] of Alias b = a.map(&.to_s).join CRYSTAL end it "invokes methods on empty array of recursive alias (2)" do run(<<-CRYSTAL).to_string.should eq("") require "prelude" alias Alias = Nil | Array(Alias) a = [] of Alias b = a.map(&.to_s).join CRYSTAL end it "invokes methods on empty array of recursive alias (3)" do run(<<-CRYSTAL).to_string.should eq("") require "prelude" alias Alias = Nil | Array(Alias) a = [] of Alias b = a.map(&.to_s).join CRYSTAL end it "casts to recursive alias" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Bar(T) end alias Foo = Int32 | Bar(Foo) a = 1.as(Foo) b = a.as(Int32) b CRYSTAL end it "casts to recursive alias" do run(<<-CRYSTAL).to_i.should eq(1) class Bar(T) def self.new(&block : -> T) end def to_i! 0 end end alias Foo = Int32 | Bar(Foo) def foo(n) if n == 0 1 else foo(n &- 1).as(Foo) end end foo(2).to_i! CRYSTAL end it "doesn't break with alias for link attributes" do result = semantic(<<-CRYSTAL) alias Foo = Int32 module Moo alias Bar = Foo alias Foo = Moo end CRYSTAL result.program.link_annotations end it "doesn't crash on cast to as recursive alias (#639)" do codegen(<<-CRYSTAL) class Foo(T) end alias Type = Int32 | Foo(Type) Foo(Type).new ptr = Pointer(Type).malloc(1_u64) ptr.value = 1.as(Type) ptr.value = 1 CRYSTAL end it "lazily solves aliases (#1346)" do run(<<-CRYSTAL) struct Proc def self.new(&block : self) block end end class Session; end alias CmdHandler = Proc(Session, Int32) class Session def foo 1 end end class SmtpSession < Session def foo 2 end end cmd = CmdHandler.new { |s| s.foo } cmd.call(SmtpSession.new) CRYSTAL end it "codegens cast to alias that includes bool" do run(<<-CRYSTAL).to_i.should eq(2) alias Foo = Bool | Array(Foo) a = false.as(Foo) if a 1 else 2 end CRYSTAL end it "overloads alias against generic (1) (#3261)" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(2) class Foo(T) end alias FooString = Foo(String) def take(foo : Foo(String)) 1 end def take(foo : FooString) 2 end take(Foo(String).new) CRYSTAL end it "overloads alias against generic (2) (#3261)" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(1) class Foo(T) end alias FooString = Foo(String) def take(foo : FooString) 2 end def take(foo : Foo(String)) 1 end take(Foo(String).new) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/and_spec.cr ================================================ require "../../spec_helper" describe "Code gen: and" do it "codegens and with bool false and false" do run("false && false", Bool).should be_false end it "codegens and with bool false and true" do run("false && true", Bool).should be_false end it "codegens and with bool true and true" do run("true && true", Bool).should be_true end it "codegens and with bool true and false" do run("true && false", Bool).should be_false end it "codegens and with bool and int 1" do run("struct Bool; def to_i!; 0; end; end; (false && 2).to_i!", Int32).should eq(0) end it "codegens and with bool and int 2" do run("struct Bool; def to_i!; 0; end; end; (true && 2).to_i!", Int32).should eq(2) end it "codegens and with primitive type other than bool" do run("1 && 2", Int32).should eq(2) end it "codegens and with primitive type other than bool with union" do run("(1 && 1.5).to_f", Float64).should eq(1.5) end it "codegens and with primitive type other than bool" do run(<<-CRYSTAL, Int32).should eq(0) struct Nil; def to_i!; 0; end; end (nil && 2).to_i! CRYSTAL end it "codegens and with nilable as left node 1" do run(<<-CRYSTAL, Int32).should eq(0) struct Nil; def to_i!; 0; end; end class Object; def to_i!; -1; end; end a = Reference.new a = nil (a && 2).to_i! CRYSTAL end it "codegens and with nilable as left node 2" do run(<<-CRYSTAL, Int32).should eq(2) class Object; def to_i!; -1; end; end a = nil a = Reference.new (a && 2).to_i! CRYSTAL end it "codegens and with non-false union as left node" do run(<<-CRYSTAL, Int32).should eq(2) a = 1.5 a = 1 (a && 2).to_i! CRYSTAL end it "codegens and with nil union as left node 1" do run(<<-CRYSTAL, Int32).should eq(2) require "nil" a = nil a = 1 (a && 2).to_i! CRYSTAL end it "codegens and with nil union as left node 2" do run(<<-CRYSTAL, Int32).should eq(0) struct Nil; def to_i!; 0; end; end a = 1 a = nil (a && 2).to_i! CRYSTAL end it "codegens and with bool union as left node 1" do run(<<-CRYSTAL, Int32).should eq(2) struct Bool; def to_i!; 0; end; end a = false a = 1 (a && 2).to_i! CRYSTAL end it "codegens and with bool union as left node 2" do run(<<-CRYSTAL, Int32).should eq(0) struct Bool; def to_i!; 0; end; end a = 1 a = false (a && 2).to_i! CRYSTAL end it "codegens and with bool union as left node 3" do run(<<-CRYSTAL, Int32).should eq(2) struct Bool; def to_i!; 0; end; end a = 1 a = true (a && 2).to_i! CRYSTAL end it "codegens and with bool union as left node 1" do run(<<-CRYSTAL, Int32).should eq(3) require "nil" struct Bool; def to_i!; 1; end; end a = false a = nil a = 2 (a && 3).to_i! CRYSTAL end it "codegens and with bool union as left node 2" do run(<<-CRYSTAL, Int32).should eq(1) require "nil" struct Bool; def to_i!; 1; end; end a = nil a = 2 a = false (a && 3).to_i! CRYSTAL end it "codegens and with bool union as left node 3" do run(<<-CRYSTAL, Int32).should eq(3) require "nil" struct Bool; def to_i!; 1; end; end a = nil a = 2 a = true (a && 3).to_i! CRYSTAL end it "codegens and with bool union as left node 4" do run(<<-CRYSTAL, Int32).should eq(0) struct Nil; def to_i!; 0; end; end struct Bool; def to_i!; 1; end; end a = 2 a = true a = nil (a && 3).to_i! CRYSTAL end it "codegens assign in right node, after must be nilable" do run(<<-CRYSTAL, Bool).should be_true a = 1 == 2 && (b = Reference.new) b.nil? CRYSTAL end it "codegens assign in right node, inside if must not be nil" do run(<<-CRYSTAL, Int32).should eq(1) struct Nil; end class Foo; def foo; 1; end; end if 1 == 1 && (b = Foo.new) b.foo else 0 end CRYSTAL end it "codegens assign in right node, after if must be nilable" do run(<<-CRYSTAL, Bool).should be_true if 1 == 2 && (b = Reference.new) end b.nil? CRYSTAL end end ================================================ FILE: spec/compiler/codegen/array_literal_spec.cr ================================================ require "../../spec_helper" describe "Code gen: array literal spec" do it "creates custom non-generic array" do run(<<-CRYSTAL).to_i.should eq(6) class Custom def initialize @value = 0 end def <<(element) @value &+= element end def value @value end end custom = Custom {1, 2, 3} custom.value CRYSTAL end it "creates custom generic array" do run(<<-CRYSTAL).to_i.should eq(6) class Custom(T) def initialize @value = 0 end def <<(element : T) @value &+= element end def value @value end end custom = Custom {1, 2, 3} custom.value CRYSTAL end it "creates custom generic array with type var" do run(<<-CRYSTAL).to_i.should eq(6) class Custom(T) def initialize @value = 0 end def <<(element : T) @value &+= element end def value @value end end custom = Custom(Int32) {1, 2, 3} custom.value CRYSTAL end it "creates custom generic array via alias" do run(<<-CRYSTAL).to_i.should eq(6) class Custom(T) def initialize @value = 0 end def <<(element : T) @value &+= element end def value @value end end alias MyCustom = Custom custom = MyCustom {1, 2, 3} custom.value CRYSTAL end it "creates custom generic array via alias (2)" do run(<<-CRYSTAL).to_i.should eq(6) class Custom(T) def initialize @value = 0 end def <<(element : T) @value &+= element end def value @value end end alias MyCustom = Custom(Int32) custom = MyCustom {1, 2, 3} custom.value CRYSTAL end it "creates custom non-generic array in nested module" do run(<<-CRYSTAL).to_i.should eq(6) class Foo::Custom def initialize @value = 0 end def <<(element) @value &+= element end def value @value end end custom = Foo::Custom {1, 2, 3} custom.value CRYSTAL end it "creates custom non-generic array in module" do run(<<-CRYSTAL).to_i.should eq(6) module Moo class Custom def initialize @value = 0 end def <<(element) @value &+= element end def value @value end end end custom = Moo::Custom {1, 2, 3} custom.value CRYSTAL end it "creates custom generic array in module (#5684)" do run(<<-CRYSTAL).to_i.should eq(6) module Moo class Custom(T) def initialize @value = 0 end def <<(element : T) @value &+= element end def value @value end end end custom = Moo::Custom {1, 2, 3} custom.value CRYSTAL end it "creates custom non-generic array, with splats" do run(<<-CRYSTAL).to_i.should eq(123456) #{enumerable_element_type} class Foo def initialize(@x : Int32) end def first 0 end def each yield @x yield @x &+ 1 end end class Custom def initialize @value = 0 end def <<(element) @value = @value &* 10 &+ element end def value @value end end custom = Custom {1, *Foo.new(2), 4, *Foo.new(5)} custom.value CRYSTAL end it "creates custom generic array, with splats" do run(<<-CRYSTAL).to_i.should eq(123456) #{enumerable_element_type} class Foo def initialize(@x : Int32) end def first 0 end def each yield @x yield @x &+ 1 end end class Custom(T) def initialize @value = 0 end def <<(element : T) @value = @value &* 10 &+ element end def value @value end end custom = Custom {1, *Foo.new(2), 4, *Foo.new(5)} custom.value CRYSTAL end it "creates typed array" do run("require \"prelude\"; typeof([1, 2] of Int8)").to_string.should eq("Array(Int8)") end it "assignment in array literal works" do run("require \"prelude\"; [a = 1]; a").to_i.should eq(1) end it "assignment in array-like literal works" do run("require \"prelude\"; Array(Int32){a = 1}; a").to_i.should eq(1) end end private def enumerable_element_type %( module Enumerable(T) def self.element_type(x) x.each { |elem| return elem } ret = uninitialized NoReturn ret end end ) end ================================================ FILE: spec/compiler/codegen/asm_spec.cr ================================================ require "../../spec_helper" describe "Code gen: asm" do # TODO: arm asm tests {% if flag?(:i386) || flag?(:x86_64) %} it "passes correct string length to LLVM" do run <<-CRYSTAL asm("// 😂😂 nop nop") CRYSTAL end it "codegens without inputs" do run(<<-CRYSTAL).to_i.should eq(1234) dst = uninitialized Int32 asm("mov $$1234, $0" : "=r"(dst)) dst CRYSTAL end it "codegens with two outputs" do run(<<-CRYSTAL).to_i.should eq(0x12345678) dst1 = uninitialized Int32 dst2 = uninitialized Int32 asm(" mov $$0x1234, $0 mov $$0x5678, $1" : "=r"(dst1), "=r"(dst2)) (dst1.unsafe_shl(16)) | dst2 CRYSTAL end it "codegens with one input" do run(<<-CRYSTAL).to_i.should eq(1234) src = 1234 dst = uninitialized Int32 asm("mov $1, $0" : "=r"(dst) : "r"(src)) dst CRYSTAL end it "codegens with two inputs" do run(<<-CRYSTAL).to_i.should eq(42) c = uninitialized Int32 a = 20 b = 22 asm( "add $2, $0" : "=r"(c) : "0"(a), "r"(b) ) c CRYSTAL end it "codegens with intel dialect" do run(<<-CRYSTAL).to_i.should eq(1234) dst = uninitialized Int32 asm("mov dword ptr [$0], 1234" :: "r"(pointerof(dst)) :: "intel") dst CRYSTAL end {% end %} end ================================================ FILE: spec/compiler/codegen/automatic_cast_spec.cr ================================================ require "../../spec_helper" describe "Code gen: automatic cast" do it "casts literal integer (Int32 -> Int64)" do run(<<-CRYSTAL).to_i.should eq(12345) def foo(x : Int64) x end foo(12345) CRYSTAL end it "casts literal integer (Int64 -> Int32, ok)" do run(<<-CRYSTAL).to_i.should eq(2147483647) def foo(x : Int32) x end foo(2147483647_i64) CRYSTAL end it "casts literal integer (Int32 -> Float32)" do run(<<-CRYSTAL).to_i.should eq(12345) def foo(x : Float32) x end foo(12345).to_i! CRYSTAL end it "casts literal integer (Int32 -> Float64)" do run(<<-CRYSTAL).to_i.should eq(12345) def foo(x : Float64) x end foo(12345).to_i! CRYSTAL end it "casts literal float (Float32 -> Float64)" do run(<<-CRYSTAL).to_i.should eq(12345) def foo(x : Float64) x end foo(12345.0_f32).to_i! CRYSTAL end it "casts literal float (Float64 -> Float32)" do run(<<-CRYSTAL).to_i.should eq(12345) def foo(x : Float32) x end foo(12345.0).to_i! CRYSTAL end it "casts symbol literal to enum" do run(<<-CRYSTAL).to_i.should eq(2) :four enum Foo One Two Three end def foo(x : Foo) x end foo(:three) CRYSTAL end it "casts Int32 to Int64 in ivar assignment" do run(<<-CRYSTAL).to_i.should eq(10) class Foo @x : Int64 def initialize @x = 10 end def x @x end end Foo.new.x CRYSTAL end it "casts Symbol to Enum in ivar assignment" do run(<<-CRYSTAL).to_i.should eq(2) enum E One Two Three end class Foo @x : E def initialize @x = :three end def x @x end end Foo.new.x CRYSTAL end it "casts Int32 to Int64 in cvar assignment" do run(<<-CRYSTAL).to_i.should eq(10) class Foo @@x : Int64 = 0_i64 def self.x @@x = 10 @@x end end Foo.x CRYSTAL end it "casts Int32 to Int64 in lvar assignment" do run(<<-CRYSTAL).to_i.should eq(123) x : Int64 x = 123 x CRYSTAL end it "casts Int32 to Int64 in ivar type declaration" do run(<<-CRYSTAL).to_i.should eq(10) class Foo @x : Int64 = 10 def x @x end end Foo.new.x CRYSTAL end it "casts Symbol to Enum in ivar type declaration" do run(<<-CRYSTAL).to_i.should eq(2) enum Color Red Green Blue end class Foo @x : Color = :blue def x @x end end Foo.new.x CRYSTAL end it "casts Int32 to Int64 in cvar type declaration" do run(<<-CRYSTAL).to_i.should eq(10) class Foo @@x : Int64 = 10 def self.x @@x end end Foo.x CRYSTAL end it "casts Int32 -> Int64 in arg restriction" do run(<<-CRYSTAL).to_i.should eq(123) def foo(x : Int64 = 123) x end foo CRYSTAL end it "casts Int32 to Int64 in ivar type declaration in generic" do run(<<-CRYSTAL).to_i.should eq(10) class Foo(T) @x : T = 10 def x @x end end Foo(Int64).new.x CRYSTAL end it "does multidispatch with automatic casting (1) (#8217)" do run(<<-CRYSTAL).to_i.should eq(10) def foo(mode : Int64, x : Int32) 10 end def foo(mode : Int64, x : String) 20 end foo(1, 1 || "a") CRYSTAL end it "does multidispatch with automatic casting (2) (#8217)" do run(<<-CRYSTAL).to_i.should eq(20) def foo(mode : Int64, x : Int32) 10 end def foo(mode : Int64, x : String) 20 end foo(1, "a" || 1) CRYSTAL end it "does multidispatch with automatic casting (3)" do run(<<-CRYSTAL).to_i.should eq(2) abstract class Foo end class Bar < Foo def foo(x : UInt8) 2 end end class Baz < Foo def foo(x : UInt8) 3 end end Bar.new.as(Foo).foo(1) CRYSTAL end it "doesn't autocast number on union (#8655)" do run(<<-CRYSTAL).to_i.should eq(255) def foo(x : UInt8 | Int32, y : Float64) x end foo(255, 60) CRYSTAL end it "casts integer variable to larger type (#9565)" do run(<<-CRYSTAL).to_i64.should eq(123) def foo(x : Int64) x end x = 123 foo(x) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/block_spec.cr ================================================ require "../../spec_helper" describe "Code gen: block" do it "generate inline" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end foo do 1 end CRYSTAL end it "passes yield arguments" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield 1 end foo do |x| x &+ 1 end CRYSTAL end it "pass arguments to yielder function" do run(<<-CRYSTAL).to_i.should eq(4) def foo(a) yield a end foo(3) do |x| x &+ 1 end CRYSTAL end it "pass self to yielder function" do run(<<-CRYSTAL).to_i.should eq(4) struct Int def foo yield self end end 3.foo do |x| x &+ 1 end CRYSTAL end it "pass self and arguments to yielder function" do run(<<-CRYSTAL).to_i.should eq(5) struct Int def foo(i) yield self, i end end 3.foo(2) do |x, i| x &+ i end CRYSTAL end it "allows access to local variables" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield end x = 1 foo do x &+ 1 end CRYSTAL end it "can access instance vars from yielder function" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @x = 1 end def foo yield @x end end Foo.new.foo do |x| x &+ 1 end CRYSTAL end it "can set instance vars from yielder function" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @x = 1 end def foo @x = yield end def value @x end end a = Foo.new a.foo { 2 } a.value CRYSTAL end it "can use instance methods from yielder function" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo yield value end def value 1 end end Foo.new.foo { |x| x &+ 1 } CRYSTAL end it "can call methods from block when yielder is an instance method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo yield end end def bar 1 end Foo.new.foo { bar } CRYSTAL end it "nested yields" do run(<<-CRYSTAL).to_i.should eq(1) def bar yield end def foo bar { yield } end a = foo { 1 } CRYSTAL end it "assigns yield to argument" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x) yield x = 1 end foo(1) { 1 } CRYSTAL end it "can use global constant" do run(<<-CRYSTAL).to_i.should eq(1) FOO = 1 def foo yield FOO end foo { } CRYSTAL end it "return from yielder function" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield return 1 end foo { } 2 CRYSTAL end it "return from block" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end def bar foo { return 1 } 2 end bar CRYSTAL end it "return from yielder function (2)" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield return 1 if true return 2 end def bar foo {} end bar CRYSTAL end it "union value of yielder function" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield a = 1.1 a = 1 a end foo {}.to_i! CRYSTAL end it "allow return from function called from yielder function" do run(<<-CRYSTAL).to_i.should eq(1) def foo return 2 end def bar yield foo 1 end bar {} CRYSTAL end it "" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield true ? return 1 : return 1.1 end foo {}.to_i! CRYSTAL end it "return from block that always returns from function that always yields inside if block" do run(<<-CRYSTAL).to_i.should eq(1) def bar yield 2 end def foo if true bar { return 1 } else 0 end end foo CRYSTAL end it "return from block that always returns from function that conditionally yields" do run(<<-CRYSTAL).to_i.should eq(1) def bar if true yield end end def foo bar { return 1 } 2 end foo CRYSTAL end it "call block from dispatch" do run(<<-CRYSTAL).to_i.should eq(1) def bar(y) yield y end def foo x = 1.1 x = 1 bar(x) { |z| z } end foo.to_i! CRYSTAL end it "call block from dispatch and use local vars" do run(<<-CRYSTAL).to_i.should eq(4) require "prelude" def bar(y) yield y end def foo total = 0 x = 1.5 bar(x) { |z| total += z } x = 1 bar(x) { |z| total += z } x = 1.5 bar(x) { |z| total += z } total end foo.to_i CRYSTAL end it "break without value returns nil" do run(<<-CRYSTAL).to_b.should be_true require "nil" require "value" def foo yield 1 end x = foo do break if 1 == 1 end x.nil? CRYSTAL end it "break block with yielder inside while" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" a = 0 10.times do a += 1 break if a > 5 end a CRYSTAL end it "break from block returns from yielder" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield yield end a = 0 foo { a &+= 1; break } a CRYSTAL end it "break from block with value" do run(<<-CRYSTAL).to_i.should eq(1) def foo while true yield a = 3 end end foo do break 1 end CRYSTAL end it "returns from block with value" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo while true yield a = 3 end end def bar foo do return 1 end end bar.to_i CRYSTAL end it "doesn't codegen after while that always yields and breaks" do run(<<-CRYSTAL).to_i.should eq(2) def foo while true yield end 1 end foo do break 2 end CRYSTAL end it "break from block with value" do run(<<-CRYSTAL).to_i.should eq(20) require "prelude" 10.times { break 20 } CRYSTAL end it "doesn't codegen call if arg yields and always breaks" do run(<<-CRYSTAL).to_i.should eq(2) require "nil" def foo 1 &+ yield end foo { break 2 }.to_i! CRYSTAL end it "codegens nested return" do run(<<-CRYSTAL).to_i.should eq(2) def bar yield a = 1 end def foo bar { yield } end def z foo { return 2 } end z CRYSTAL end it "codegens nested break" do run(<<-CRYSTAL).to_i.should eq(2) def bar yield a = 1 end def foo bar { yield } end foo { break 2 } CRYSTAL end it "codegens call with block with call with arg that yields" do run(<<-CRYSTAL).to_i.should eq(3) def bar yield a = 2 end def foo bar { 1 &+ yield } end foo { break 3 } CRYSTAL end it "can break without value from yielder that returns nilable (1)" do run(<<-CRYSTAL).to_b.should be_true def foo yield "" end a = foo do break end a.nil? CRYSTAL end it "can break without value from yielder that returns nilable (2)" do run(<<-CRYSTAL).to_b.should be_true def foo yield "" end a = foo do break nil end a.nil? CRYSTAL end it "break with value from yielder that returns a nilable" do run(<<-CRYSTAL).to_b.should be_false def foo yield "" end a = foo do break if false break "" end a.nil? CRYSTAL end it "can use self inside a block called from dispatch" do run(<<-CRYSTAL).to_i.should eq(123) struct Nil; def to_i!; 0; end; end class Foo def do; yield; end end class Bar < Foo end class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end struct Int def foo x = Foo.new x = Bar.new x.do { Global.x = self } end end 123.foo Global.x.to_i! CRYSTAL end it "return from block called from dispatch" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def do; yield; end end class Bar < Foo end def foo x = Foo.new x = Bar.new x.do { return 1 } 0 end foo CRYSTAL end it "breaks from while in function called from block" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield end def bar while true break 1 end 2 end foo do bar end CRYSTAL end it "allows modifying yielded value (with literal)" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield 1 end foo { |x| x = 2; x } CRYSTAL end it "allows modifying yielded value (with variable)" do run(<<-CRYSTAL).to_i.should eq(1) def foo a = 1 yield a a end foo { |x| x = 2; x } CRYSTAL end it "it yields nil from another call" do run(<<-CRYSTAL) require "bool" def foo(key, default) foo(key) { default } end def foo(key) if !(true) return yield key end yield key end foo(1, nil) CRYSTAL end it "allows yield from dispatch call" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x : Value) yield 1 end def foo(x : Int) yield 2 end def bar a = 1; a = 1.1 foo(a) do |i| yield i end end x = 0 bar { |i| x = i } x CRYSTAL end it "block with nilable type" do run(<<-CRYSTAL) class Foo def foo yield 1 end end class Bar def foo yield 2 Reference.new end end a = Foo.new || Bar.new a.foo {} CRYSTAL end it "block with nilable type 2" do run(<<-CRYSTAL) class Foo def foo yield 1 nil end end class Bar def foo yield 2 Reference.new end end a = Foo.new || Bar.new a.foo {} CRYSTAL end it "codegens block with nilable type with return (1)" do run(<<-CRYSTAL).to_b.should be_true def foo if yield return Reference.new end nil end foo { false }.nil? CRYSTAL end it "codegens block with nilable type with return (2)" do run(<<-CRYSTAL).to_b.should be_false def foo if yield return nil end Reference.new end foo { false }.nil? CRYSTAL end it "codegens block with union with return" do run(<<-CRYSTAL) def foo yield return 1 if 1 == 2 nil end x = foo { } 1 CRYSTAL end it "codegens if with call with block (ssa issue)" do run(<<-CRYSTAL).to_i.should eq(3) def bar yield end def foo if 1 == 2 bar do x = 1 end else 3 end end foo CRYSTAL end it "codegens block with return and yield and no return" do run(<<-CRYSTAL).to_i.should eq(2) lib LibC fun exit : NoReturn end def foo(key) foo(key) { LibC.exit } end def foo(key) if 1 == 1 return 2 end yield end foo 1 CRYSTAL end it "codegens while/break inside block" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end foo do while true break end 1 end CRYSTAL end it "codegens block with union arg (1)" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield 1 || 1.5 end foo { |x| x }.to_i! CRYSTAL end it "codegens block with union arg (2)" do run(<<-CRYSTAL).to_i.should eq(1) struct Number def abs self end end class Foo(T) def initialize(x : T) @x = x end def each yield @x end end a = Foo.new(1) || Foo.new(1.5) a.each do |x| x.abs end.to_i! CRYSTAL end it "codegens block with virtual type arg" do run(<<-CRYSTAL).to_i.should eq(1) class Var(T) def initialize(x : T) @x = x end def each yield @x end end class Foo def bar 1 end end class Bar < Foo def bar 2 end end a = Var.new(Foo.new) || Var.new(Bar.new) a.each do |x| x.bar end CRYSTAL end it "codegens call with blocks of different type without args" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end foo { 1.1 } foo { 1 } CRYSTAL end it "codegens dispatch with block and break (1)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo(T) def initialize(@x : T) end def each yield @x end end n = 0 f = Foo.new(1) || Foo.new(1.5) f.each do |x| break if x > 2 n += x end n.to_i CRYSTAL end it "codegens dispatch with block and break (2)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" a = [1, 2, 3] || [1.5] n = 0 a.each do |x| break if x > 2 n += x end n.to_i CRYSTAL end it "codegens block call when argument type changes" do run(<<-CRYSTAL) def foo(x) while 1 == 2 x = 1.5 yield end end foo(1) do end CRYSTAL end it "returns void when called with block" do run(<<-CRYSTAL) fun foo : Void end def bar yield foo end bar {} CRYSTAL end it "executes yield expression if no arg is given for block" do run(<<-CRYSTAL).to_i.should eq(2) def foo a = 1 yield (a = 2) a end foo { } CRYSTAL end it "codegens bug with block and arg and var" do run(<<-CRYSTAL).to_i.should eq(65) def foo yield 1 end foo { |a| x = a } foo do a = 'A' a.ord end CRYSTAL end it "allows using var as block arg with outer var" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield 'a' end a = foo do |a| 1 end CRYSTAL end it "allows initialize with yield (#224)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @x : Int32 def initialize @x = yield 1 end def x @x end end foo = Foo.new do |a| a &+ 1 end foo.x CRYSTAL end it "uses block inside array literal (bug)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo yield 1 end ary = [foo { |x| x.abs }] ary[0] CRYSTAL end it "codegens method invocation on a object of a captured block with a type that was never instantiated" do codegen(<<-CRYSTAL) class Bar def initialize(@bar : NoReturn) end def bar @bar end def baz(x) end end def foo(&block : Bar ->) block end def method(bar) bar.bar end foo do |bar| bar.baz method(bar).baz end CRYSTAL end it "codegens method invocation on a object of a captured block with a type that was never instantiated (2)" do codegen(<<-CRYSTAL) class Bar def initialize(@bar : NoReturn) end def bar @bar end end def foo(&block : Bar ->) block end def method(bar) bar.bar end def baz(x) end foo do |bar| baz method(bar).baz end CRYSTAL end it "codegens bug with yield not_nil! that is never not nil" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC fun exit(Int32) : NoReturn end class Object def not_nil! self end end struct Nil def not_nil! LibC.exit(1) end def to_i! 0 end end def foo key = nil if 1 == 2 yield key.not_nil! end yield 1 end extra = nil foo do |key| if 1 == 1 extra = 1 extra &+ key end end extra.to_i! CRYSTAL end it "uses block var with same name as local var" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield "hello" end a = 1 foo do |a| a end a CRYSTAL end it "doesn't crash on untyped array to_s" do run(<<-CRYSTAL).to_string.should eq("[]") require "prelude" class Bar(T) end class Foo(K) @foo : Nil def foo Array(typeof(yield @foo.not_nil!)).new end end Foo(Int32).new.foo { |k| k + 1 }.to_s CRYSTAL end it "codegens block which always breaks but never enters (#494)" do run(<<-CRYSTAL).to_i.should eq(3) def foo while 1 == 2 yield end 3 end foo do break 10 end CRYSTAL end it "codegens block bug with conditional next and unconditional break (1)" do run(<<-CRYSTAL).to_i.should eq(6) def foo yield 1 yield 2 yield 3 end a = 0 foo do |x| a &+= x next if true break end a CRYSTAL end it "codegens block bug with conditional next and unconditional break (2)" do run(<<-CRYSTAL).to_i.should eq(6) def foo yield 1 yield 2 yield 3 end a = 0 foo do |x| a &+= x next if 1 == 1 break end a CRYSTAL end it "codegens block bug with conditional next and unconditional break (3)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo a = 1234 a = yield 1 Global.x = a a end foo do |x| next x if 1 == 1 break 0 end Global.x CRYSTAL end it "codegens block bug with conditional next and unconditional break (4)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo bar(yield 1) end def bar(x) Global.x = x end foo do |x| next x if 1 == 1 break 0 end Global.x CRYSTAL end it "returns from proc literal" do run(<<-CRYSTAL).to_i.should eq(10) foo = ->{ if 1 == 1 return 10 end 20 } foo.call CRYSTAL end it "does next from captured block" do run(<<-CRYSTAL).to_i.should eq(10) def foo(&block : -> T) forall T block end f = foo do if 1 == 1 next 10 end next 20 end f.call CRYSTAL end it "codegens captured block with next inside yielded block (#2097)" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield end def bar(&block : -> Int32) block end foo do block = bar do next 123 end block.call end CRYSTAL end it "codegens captured block that returns union, but proc only returns a single type" do run(<<-CRYSTAL).to_string.should eq("foo") def run_callbacks(&block : -> Int32 | String) block.call end f = run_callbacks { "foo" } if f.is_a?(String) f else "oops" end CRYSTAL end it "yields inside yield (#682)" do run(<<-CRYSTAL).to_i.should eq(4) def foo yield(1, (yield 3)) end a = 0 foo do |x| a &+= x end a CRYSTAL end it "yields splat" do run(<<-CRYSTAL).to_i.should eq(6) def foo tup = {1, 2, 3} yield *tup end foo do |x, y, z| x &+ y &+ z end CRYSTAL end it "yields more exps than block arg, through splat" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield *{1, 2} end foo do |x| x end CRYSTAL end it "uses splat in block argument" do run(<<-CRYSTAL).to_i.should eq(6) def foo yield 1, 2, 3 end foo do |*args| args[0] &+ args[1] &+ args[2] end CRYSTAL end it "uses splat in block argument, many args" do run(<<-CRYSTAL).to_i.should eq(((((1 + 2) * 3) - 4) * 5) - 6) def foo yield 1, 2, 3, 4, 5, 6 end foo do |x, y, *z, w| ((((x &+ y) &* z[0]) &- z[1]) &* z[2]) &- w end CRYSTAL end it "uses block splat argument with union types" do run(<<-CRYSTAL).to_i.should eq(3) def foo yield 1 yield 2.5 end total = 0 foo do |*args| total &+= args[0].to_i! end total CRYSTAL end it "works if block has both splat and non-splat underscore parameters" do run(<<-CRYSTAL, Int32).should eq(34) def foo(&) yield 1, 2, 4, 8, 16, 32 end foo do |_, a, *_, b| a &+ b end CRYSTAL end it "works if block has both splat parameter and multiple non-splat underscore parameters" do run(<<-CRYSTAL, Int32).should eq(40) def foo(&) yield 1, 2, 4, 8, "", 32 end foo do |_, *a, _, b| a[2] &+ b end CRYSTAL end it "auto-unpacks tuple" do run(<<-CRYSTAL).to_i.should eq((1 + 2) * 4) def foo tup = {1, 2, 4} yield tup end foo do |x, y, z| (x &+ y) &* z end CRYSTAL end it "unpacks tuple but doesn't override local variables" do run(<<-CRYSTAL).to_i.should eq(10) def foo yield({10, 20}, {30, 40}) end x = 1 y = 2 z = 3 w = 4 foo do |(x, y), (z, w)| end x &+ y &+ z &+ w CRYSTAL end it "codegens block with multiple underscores (#3054)" do run(<<-CRYSTAL).to_i.should eq(3) def foo(&block : Int32, Int32 -> Int32) block.call(1, 2) end foo do |_, _| 3 end CRYSTAL end it "breaks in var assignment (#3364)" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield 456 end foo do a = nil || break 123 end CRYSTAL end it "nexts in var assignment (#3364)" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield end foo do a = nil || next 123 end CRYSTAL end it "dispatches with captured and non-captured block (#3969)" do run(<<-CRYSTAL).to_i.should eq(3) def fn(x : Int32, &block) x end def fn(x : Char, &block : -> Int32) block.call end a = fn(1 || 'a') { 2 } b = fn('a' || 1) { 2 } a &+ b CRYSTAL end it "codegens block with repeated underscore and different types (#4711)" do codegen(<<-CRYSTAL) def foo yield('0', 0) end foo{|_, _| } CRYSTAL end it "doesn't crash on yield exp without a type (#8100)" do codegen(<<-CRYSTAL) def foo x = 1 if x.is_a?(Char) yield x else yield x end end foo { |x| } CRYSTAL end it "clears nilable var before inlining block method (#10087)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @@x = 0 def self.bar i = 0 while i < 2 yield i i &+= 1 end @@x end def self.foo(x) if x == 0 bug = "Hello" end if bug @@x &+= 1 end yield end end Foo.bar do |z| Foo.foo(z) { } end CRYSTAL end it "(bug) doesn't set needs_value to true on every yield (#12442)" do run(<<-CRYSTAL).to_i.should eq(1) def foo if true yield end 1 end foo do 1 end CRYSTAL end it "doesn't crash if yield exp has no type (#12670)" do codegen(<<-CRYSTAL) def foo : String? end def bar while res = foo yield res end end bar do |res| res end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/c_abi/c_abi_spec.cr ================================================ require "../../../spec_helper" describe "Code gen: C ABI" do it "passes struct less than 64 bits (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct s { char x; short y; }; int foo(struct s a) { return a.x + a.y; } C lib LibFoo struct Struct x : Int8 y : Int16 end fun foo(s : Struct) : Int32 end s = LibFoo::Struct.new x: 1_i8, y: 2_i16 LibFoo.foo(s) CRYSTAL end it "passes struct between 64 and 128 bits (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct s { long long x; short y; }; long long foo(struct s a) { return a.x + a.y; } C lib LibFoo struct Struct x : Int64 y : Int16 end fun foo(s : Struct) : Int64 end s = LibFoo::Struct.new x: 1_i64, y: 2_i16 LibFoo.foo(s) CRYSTAL end it "passes struct bigger than 128 bits (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(6)) struct s { long long x; long long y; char z; }; long long foo(struct s a) { return a.x + a.y + a.z; } C lib LibFoo struct Struct x : Int64 y : Int64 z : Int8 end fun foo(s : Struct) : Int64 end s = LibFoo::Struct.new x: 1_i64, y: 2_i64, z: 3_i8 LibFoo.foo(s) CRYSTAL end it "passes struct after many other args (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_string.should eq("28")) struct s { long long x, y; }; long long foo(long long a, long long b, long long c, long long d, long long e, struct s v) { return a + b + c + d + e + v.x + v.y; } C lib LibFoo struct S x : Int64 y : Int64 end fun foo(a : Int64, b : Int64, c : Int64, d : Int64, e : Int64, v : S) : Int64 end v = LibFoo::S.new(x: 6, y: 7) LibFoo.foo(1, 2, 3, 4, 5, v) CRYSTAL end it "passes struct after many other args when returning a large struct (sret return type)" do test_c(<<-C, <<-CRYSTAL, &.to_string.should eq("[6, 7, 10]")) struct s { long long x, y; }; struct t { long long x, y, z; }; struct t foo(long long a, long long b, long long c, long long d, struct s v) { return (struct t){ v.x, v.y, a + b + c + d }; } C lib LibFoo struct S x : Int64 y : Int64 end struct T x : Int64 y : Int64 z : Int64 end fun foo(a : Int64, b : Int64, c : Int64, d : Int64, v : S) : T end v = LibFoo::S.new(x: 6, y: 7) w = LibFoo.foo(1, 2, 3, 4, v) [w.x, w.y, w.z] CRYSTAL end it "returns struct less than 64 bits (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct s { char x; short y; }; struct s foo() { struct s a = {1, 2}; return a; } C lib LibFoo struct Struct x : Int8 y : Int16 end fun foo : Struct end str = LibFoo.foo str.x.to_i + str.y.to_i CRYSTAL end it "returns struct between 64 and 128 bits (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct s { long long x; short y; }; struct s foo() { struct s a = {1, 2}; return a; } C lib LibFoo struct Struct x : Int64 y : Int16 end fun foo : Struct end str = LibFoo.foo (str.x + str.y).to_i32 CRYSTAL end it "returns struct bigger than 128 bits with sret" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(6)) struct s { long long x; long long y; char z; }; struct s foo(int z) { struct s a = {1, 2, z}; return a; } C lib LibFoo struct Struct x : Int64 y : Int64 z : Int8 end fun foo(w : Int32) : Struct end str = LibFoo.foo(3) (str.x + str.y + str.z).to_i32 CRYSTAL end it "accepts large struct in a callback (for real)" do test_c(<<-C, <<-CRYSTAL, &.to_string.should eq("6")) struct s { long long x, y, z; }; void ccaller(void (*func)(struct s)) { struct s v = {1, 2, 3}; func(v); } C lib LibFoo struct S x : Int64 y : Int64 z : Int64 end fun ccaller(func : (S) ->) end module Global class_property x = 0i64 end fun callback(v : LibFoo::S) Global.x = v.x &+ v.y &+ v.z end LibFoo.ccaller(->callback) Global.x CRYSTAL end it "promotes variadic args (float to double)" do test_c(<<-C, <<-CRYSTAL, &.to_f64.should eq(1.0)) #include double foo(int n, ...) { va_list args; va_start(args, n); return va_arg(args, double); } C lib LibFoo fun foo(n : Int32, ...) : Float64 end LibFoo.foo(1, 1.0_f32) CRYSTAL end [{"i8", -123}, {"u8", 255}, {"i16", -123}, {"u16", 65535}, ].each do |int_kind, int_value| it "promotes variadic args (#{int_kind} to i32) (#9742)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(int_value)) #include int foo(int n, ...) { va_list args; va_start(args, n); return va_arg(args, int); } C lib LibFoo fun foo(n : Int32, ...) : Int32 end LibFoo.foo(1, #{int_value}_#{int_kind}) CRYSTAL end end end ================================================ FILE: spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr ================================================ {% skip_file unless flag?(:x86_64) && !flag?(:win32) %} require "../../../spec_helper" describe "Code gen: C ABI x86_64" do it "passes struct less than 64 bits as { i64 }" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int8 y : Int16 end fun foo(s : Struct) end s = LibFoo::Struct.new LibFoo.foo(s) CRYSTAL str = mod.to_s str.should contain("call void @foo({ i64 }") str.should contain("declare void @foo({ i64 })") end it "passes struct less than 64 bits as { i64 } in varargs" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int8 y : Int16 end fun foo(...) end s = LibFoo::Struct.new LibFoo.foo(s) CRYSTAL str = mod.to_s str.should contain("call void (...)") end it "passes struct between 64 and 128 bits as { i64, i64 }" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int64 y : Int16 end fun foo(s : Struct) end s = LibFoo::Struct.new LibFoo.foo(s) CRYSTAL str = mod.to_s str.should contain("call void @foo({ i64, i64 }") str.should contain("declare void @foo({ i64, i64 })") end it "passes struct between 64 and 128 bits as { i64, i64 } (with multiple modules/contexts)" do codegen(<<-CRYSTAL) require "prelude" lib LibFoo struct Struct x : Int64 y : Int16 end fun foo(s : Struct) end module Moo def self.moo s = LibFoo::Struct.new LibFoo.foo(s) end end Moo.moo CRYSTAL end it "passes struct bigger than128 bits with byval" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int64 y : Int64 z : Int8 end fun foo(s : Struct) end s = LibFoo::Struct.new LibFoo.foo(s) CRYSTAL str = mod.to_s str.scan(/byval/).size.should eq(2) end it "returns struct less than 64 bits as { i64 }" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int8 y : Int16 end fun foo : Struct end str = LibFoo.foo CRYSTAL str = mod.to_s str.should contain("call { i64 } @foo()") str.should contain("declare { i64 } @foo()") end it "returns struct between 64 and 128 bits as { i64, i64 }" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int64 y : Int16 end fun foo : Struct end str = LibFoo.foo CRYSTAL str = mod.to_s str.should contain("call { i64, i64 } @foo()") str.should contain("declare { i64, i64 } @foo()") end it "returns struct bigger than 128 bits with sret" do mod = codegen(<<-CRYSTAL) lib LibFoo struct Struct x : Int64 y : Int64 z : Int8 end fun foo(w : Int32) : Struct end str = LibFoo.foo(1) CRYSTAL str = mod.to_s str.scan(/sret/).size.should eq(2) if LibLLVM::IS_LT_120 str.should contain("sret, i32") # sret goes as first argument else str.should contain("sret(%\"struct.LibFoo::Struct\") %0, i32") # sret goes as first argument end end end ================================================ FILE: spec/compiler/codegen/c_enum_spec.cr ================================================ require "../../spec_helper" CodeGenCEnumString = "lib LibFoo; enum Bar; X; Y; Z = 10; W; end end" describe "Code gen: c enum" do it "codegens enum value" do run("#{CodeGenCEnumString}; LibFoo::Bar::X").to_i.should eq(0) end it "codegens enum value 2" do run("#{CodeGenCEnumString}; LibFoo::Bar::Y").to_i.should eq(1) end it "codegens enum value 3" do run("#{CodeGenCEnumString}; LibFoo::Bar::Z").to_i.should eq(10) end it "codegens enum value 4" do run("#{CodeGenCEnumString}; LibFoo::Bar::W").to_i.should eq(11) end [ {"+1", 1}, {"-1", -1}, {"~1", -2}, {"1 + 2", 3}, {"3 - 2", 1}, {"3 * 2", 6}, {"1 &+ 2", 3}, {"3 &- 2", 1}, {"3 &* 2", 6}, # {"10 / 2", 5}, # MathInterpreter only works with Integer and 10 / 2 : Float {"10 // 2", 5}, {"1 << 3", 8}, {"100 >> 3", 12}, {"10 & 3", 2}, {"10 | 3", 11}, {"10 ^ 3", 9}, {"(1 + 2) * 3", 9}, {"10 % 3", 1}, ].each do |(code, expected)| it "codegens enum with #{code} " do run(<<-CRYSTAL).to_i.should eq(expected) lib LibFoo enum Bar X = #{code} end end LibFoo::Bar::X CRYSTAL end end it "codegens enum that refers to another enum constant" do run(<<-CRYSTAL).to_i.should eq(3) lib LibFoo enum Bar A = 1 B = A + 1 C = B + 1 end end LibFoo::Bar::C CRYSTAL end it "codegens enum that refers to another constant" do run(<<-CRYSTAL).to_i.should eq(12) lib LibFoo X = 10 enum Bar A = X B = A + 1 C = B + 1 end end LibFoo::Bar::C CRYSTAL end end ================================================ FILE: spec/compiler/codegen/c_struct_spec.cr ================================================ require "../../spec_helper" CodeGenStructString = "lib LibFoo; struct Bar; x : Int32; y : Float32; end; end" describe "Code gen: struct" do it "codegens struct property default value" do run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.x").to_i.should eq(0) end it "codegens struct property setter" do run("#{CodeGenStructString}; bar = LibFoo::Bar.new; bar.y = 2.5_f32; bar.y").to_f32.should eq(2.5) end it "codegens struct property setter via pointer" do run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.y = 2.5_f32; bar.value.y").to_f32.should eq(2.5) end it "codegens struct property setter via pointer" do run("#{CodeGenStructString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.y = 2.5_f32; bar.value.y").to_f32.should eq(2.5) end it "codegens set struct value with constant" do run("#{CodeGenStructString}; CONST = 1; bar = LibFoo::Bar.new; bar.x = CONST; bar.x").to_i.should eq(1) end it "codegens union inside struct" do run(<<-CRYSTAL).to_i.should eq(10) lib LibFoo union Bar x : Int32 y : Int64 end struct Baz lala : Bar end end a = Pointer(LibFoo::Baz).malloc(1_u64) a.value.lala.x = 10 a.value.lala.x CRYSTAL end it "codegens struct get inside struct" do run(<<-CRYSTAL).to_i.should eq(2) lib LibC struct Bar y : Int32 end struct Foo x : Int32 bar : Bar end end foo = Pointer(LibC::Foo).malloc(1_u64) (foo.as(Int32*) + 1_i64).value = 2 foo.value.bar.y CRYSTAL end it "codegens struct set inside struct" do run(<<-CRYSTAL).to_i.should eq(2) lib LibC struct Bar y : Int32 end struct Foo x : Int32 bar : Bar end end foo = Pointer(LibC::Foo).malloc(1_u64) bar = LibC::Bar.new bar.y = 2 foo.value.bar = bar foo.value.bar.y CRYSTAL end it "codegens pointer malloc of struct" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC struct Foo x : Int32 end end p = Pointer(LibC::Foo).malloc(1_u64) p.value.x = 1 p.value.x CRYSTAL end it "passes struct to method (1)" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC struct Foo x : Int32 end end def foo(f) f.x = 2 f end f1 = LibC::Foo.new f1.x = 1 f2 = foo(f1) f1.x CRYSTAL end it "passes struct to method (2)" do run(<<-CRYSTAL).to_i.should eq(2) lib LibC struct Foo x : Int32 end end def foo(f) f.x = 2 f end f1 = LibC::Foo.new f1.x = 1 f2 = foo(f1) f2.x CRYSTAL end it "codegens struct access with -> and then ." do run(<<-CRYSTAL).to_i.should eq(0) lib LibC struct ScalarEvent x : Int32 end union EventData scalar : ScalarEvent end struct Event data : EventData end end e = Pointer(LibC::Event).malloc(1_u64) e.value.data.scalar.x CRYSTAL end it "yields struct via ->" do run(<<-CRYSTAL).to_i.should eq(0) lib LibC struct ScalarEvent x : Int32 end union EventData scalar : ScalarEvent end struct Event data : EventData end end def foo e = Pointer(LibC::Event).malloc(1_u64) yield e.value.data end foo do |data| data.scalar.x end CRYSTAL end it "codegens assign struct to union" do run(<<-CRYSTAL).to_b.should be_true lib LibFoo struct Coco x : Int32 end end x = LibFoo::Coco.new c = x || 0 c.is_a?(LibFoo::Coco) CRYSTAL end it "codegens passing pointerof(struct) to fun" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC struct Foo a : Int32 end end fun foo(x : LibC::Foo*) : Int32 x.value.a end f = LibC::Foo.new f.a = 1 foo pointerof(f) CRYSTAL end it "builds struct setter with fun type (1)" do codegen(<<-CRYSTAL) require "prelude" lib LibC struct Foo x : -> end end foo = LibC::Foo.new foo.x = -> { } CRYSTAL end it "builds struct setter with fun type (2)" do codegen(<<-CRYSTAL) require "prelude" lib LibC struct Foo x : -> end end foo = Pointer(LibC::Foo).malloc(1) foo.value.x = -> { } CRYSTAL end it "allows using named arguments for new" do run(<<-CRYSTAL).to_i.should eq(3) lib LibC struct Point x, y : Int32 end end point = LibC::Point.new x: 1, y: 2 point.x &+ point.y CRYSTAL end it "does to_s" do run(<<-CRYSTAL).to_string.should eq("LibFoo::Point(@x=1, @y=2)") require "prelude" lib LibFoo struct Point x, y : Int32 end end point = LibFoo::Point.new x: 1, y: 2 point.to_s CRYSTAL end it "can access instance var from the outside (#1092)" do run(<<-CRYSTAL).to_i.should eq(123) lib LibFoo struct Foo x : Int32 end end f = LibFoo::Foo.new x: 123 f.@x CRYSTAL end it "automatically converts numeric type in struct field assignment" do run(<<-CRYSTAL).to_i.should eq(123) lib LibFoo struct Foo x : Int32 end end foo = LibFoo::Foo.new foo.x = 123_u8 foo.x CRYSTAL end it "automatically converts numeric union type in struct field assignment" do run(<<-CRYSTAL).to_i.should eq(57) lib LibFoo struct Foo x : Int8 end end a = 12345 || 12346_u16 foo = LibFoo::Foo.new foo.x = a foo.x CRYSTAL end it "automatically converts nil to pointer" do run(<<-CRYSTAL).to_i.should eq(0) lib LibFoo struct Foo x : Int32* end end foo = LibFoo::Foo.new foo.x = Pointer(Int32).new(1234_u64) foo.x = nil foo.x.address CRYSTAL end it "automatically converts by invoking to_unsafe" do run(<<-CRYSTAL).to_i.should eq(123) lib LibFoo struct Foo x : Int32 end end class Foo def to_unsafe 123 end end foo = LibFoo::Foo.new foo.x = Foo.new foo.x CRYSTAL end it "sets instance var to proc" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" lib LibFoo struct Foo x : Int32 -> Int32 end end struct LibFoo::Foo def set(f) @x = f end end foo = LibFoo::Foo.new foo.set(->(x : Int32) { x + 1 }) foo.x.call(1) CRYSTAL end it "can access member of uninitialized struct behind type (#8774)" do run(<<-CRYSTAL) lib LibFoo struct Foo x : Int32 end type FooT = Foo end foo = uninitialized LibFoo::FooT foo.x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/c_union_spec.cr ================================================ require "../../spec_helper" CodeGenUnionString = "lib LibFoo; union Bar; x : Int32; y : Int64; z : Float32; end; end" describe "Code gen: c union" do it "codegens union property default value" do run("#{CodeGenUnionString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.x").to_i.should eq(0) end it "codegens union property default value 2" do run("#{CodeGenUnionString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.z").to_f32.should eq(0) end it "codegens union property setter 1" do run("#{CodeGenUnionString}; bar = LibFoo::Bar.new; bar.x = 42; bar.x").to_i.should eq(42) end it "codegens union property setter 2" do run("#{CodeGenUnionString}; bar = LibFoo::Bar.new; bar.z = 42.0_f32; bar.z").to_f32.should eq(42.0) end it "codegens union property setter 1 via pointer" do run("#{CodeGenUnionString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.x = 42; bar.value.x").to_i.should eq(42) end it "codegens union property setter 2 via pointer" do run("#{CodeGenUnionString}; bar = Pointer(LibFoo::Bar).malloc(1_u64); bar.value.z = 42.0_f32; bar.value.z").to_f32.should eq(42.0) end it "codegens struct inside union" do run(<<-CRYSTAL).to_i.should eq(10) lib LibFoo struct Baz lele : Int64 lala : Int32 end union Bar x : Int32 y : Int64 z : Baz end end a = Pointer(LibFoo::Bar).malloc(1_u64) a.value.z = LibFoo::Baz.new a.value.z.lala = 10 a.value.z.lala CRYSTAL end it "codegens assign c union to union" do run(<<-CRYSTAL).to_i.should eq(10) lib LibFoo union Bar x : Int32 end end bar = LibFoo::Bar.new bar.x = 10 x = bar || nil if x x.x else 1 end CRYSTAL end it "builds union setter with fun type" do codegen(<<-CRYSTAL) require "prelude" lib LibC union Foo x : -> end end foo = LibC::Foo.new foo.x = -> { } CRYSTAL end it "does to_s" do run(<<-CRYSTAL).to_string.should eq("LibNVG::Color(@array=0)") require "prelude" lib LibNVG union Color array: Int32 end end color = LibNVG::Color.new color.to_s CRYSTAL end it "automatically converts numeric type in field assignment" do run(<<-CRYSTAL).to_i.should eq(57) lib LibFoo union Foo x : Int8 end end a = 12345 foo = LibFoo::Foo.new foo.x = a foo.x CRYSTAL end it "automatically converts numeric union type in field assignment" do run(<<-CRYSTAL).to_i.should eq(57) lib LibFoo union Foo x : Int8 end end a = 12345 || 12346_u16 foo = LibFoo::Foo.new foo.x = a foo.x CRYSTAL end it "automatically converts by invoking to_unsafe" do run(<<-CRYSTAL).to_i.should eq(123) lib LibFoo union Foo x : Int32 end end class Foo def to_unsafe 123 end end foo = LibFoo::Foo.new foo.x = Foo.new foo.x CRYSTAL end it "aligns to the member with biggest align requirements" do run(<<-CRYSTAL).to_i.should eq(0x5858) lib LibFoo union Foo bytes : UInt8[4] short : UInt16 end struct Bar a : Int8 b : Foo end end class String def to_unsafe pointerof(@c) end end str = "00XX0" foo = str.to_unsafe.as(LibFoo::Bar*) foo.value.b.short.to_i CRYSTAL end it "fills union type to the max size" do run(<<-CRYSTAL).to_i.should eq(6) lib LibFoo union Foo bytes : UInt8[4] short : UInt16 end struct Bar a : Int8 b : Foo end end sizeof(LibFoo::Bar) CRYSTAL end it "reads union instance var" do run(<<-CRYSTAL).to_i.should eq(42) lib LibFoo union Foo char : Char int : Int32 end end struct LibFoo::Foo def read_int @int end end foo = LibFoo::Foo.new foo.int = 42 foo.read_int CRYSTAL end it "moves unions around correctly (#12550)" do run(<<-CRYSTAL).to_i.should eq((1..6).sum) require "prelude" lib Lib struct Foo x : UInt8 y : UInt16 end union Bar foo : Foo padding : UInt8[6] # larger than `Foo` end end def foo a = uninitialized Lib::Bar a.padding.fill { |i| 1_u8 + i } a end foo.padding.sum CRYSTAL end end ================================================ FILE: spec/compiler/codegen/case_spec.cr ================================================ require "../../spec_helper" describe "Code gen: case" do it "codegens case with one condition" do run("require \"prelude\"; case 1; when 1; 2; else; 3; end").to_i.should eq(2) end it "codegens case with two conditions" do run("require \"prelude\"; case 1; when 0, 1; 2; else; 3; end").to_i.should eq(2) end it "codegens case with else" do run("require \"prelude\"; case 1; when 0; 2; else; 3; end").to_i.should eq(3) end it "codegens case without whens but else" do run("require \"prelude\"; case 1; else; 2; end").to_i.should eq(2) end it "codegens case that always returns" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" def foo if true case 0 when 1; return 2 else return 3 end end 4 end foo CRYSTAL end it "codegens case when cond is a call" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" def foo 1 end case foo when 2 1 when 1 2 else 3 end CRYSTAL end it "codegens case with class" do run(<<-CRYSTAL).to_i.should eq(-1) struct Nil; def to_i!; 0; end; end struct Int32 def foo self end end a = -1 || 'a' case a when Int32 a.foo when Char a.ord end.to_i! CRYSTAL end it "codegens value-less case" do run(<<-CRYSTAL).to_i.should eq(2) case when 1 == 2 1 when 2 == 2 2 else 3 end CRYSTAL end it "codegens case when constant bug (#1028)" do run(<<-CRYSTAL).to_i.should eq(2) struct Nil def ===(other) self.is_a?(Reference) && other.is_a?(Reference) end end CONST = nil case nil when CONST 1 else 2 end CRYSTAL end it "does case when with metaclass" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end class Bar def self.bar 2 end end foobar = Bar || Foo case foobar when Foo.class foobar.foo when Bar.class foobar.bar else 3 end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/cast_spec.cr ================================================ require "../../spec_helper" describe "Code gen: cast" do it "allows casting object to pointer and back" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end def x @x end end f = Foo.new(1) p = f.as(Void*) f = p.as(Foo) f.x CRYSTAL end it "casts from int to int" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 b = a.as(Int32) b.abs CRYSTAL end it "casts from union to single type" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 || 'a' b = a.as(Int32) b.abs CRYSTAL end it "casts from union to single type raises TypeCastError" do run(<<-CRYSTAL).to_b.should be_true require "prelude" a = 1 || 'a' begin a.as(Char) false rescue ex ex.message.not_nil!.includes?("Cast from Int32 to Char failed") && (ex.class == TypeCastError) end CRYSTAL end it "casts from union to another union" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 || 1.5 || 'a' b = a.as(Int32 | Float64) b.abs.to_i CRYSTAL end it "casts from union to another union raises TypeCastError" do run(<<-CRYSTAL).to_b.should be_true require "prelude" a = 1 || 1.5 || 'a' begin a.as(Float64 | Char) false rescue ex ex.message.not_nil!.includes?("Cast from Int32 to (Char | Float64) failed") && (ex.class == TypeCastError) end CRYSTAL end it "upcasts from union to union with different alignment" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 || 2_i64 a.as(Int32 | Int64 | Int128) CRYSTAL end it "downcasts from union to union with different alignment" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 || 2_i64 || 3_i128 a.as(Int32 | Int64) CRYSTAL end it "sidecasts from union to union with different alignment" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1 || 2_i64 a.as(Int32 | Int128) CRYSTAL end it "doesn't corrupt stack when downcasting union to union with different alignment (#14285)" do run(<<-CRYSTAL).to_b.should be_true struct Time2 def initialize(@seconds : Int64) @nanoseconds = uninitialized UInt32[3] end def <(other : Time2) : Bool @seconds < other.@seconds end end class Constraints::Range def initialize(@min : Int128 | Time2 | Nil) end end def validate(value : Time2, constraint) : Bool min = constraint.@min if min.is_a?(Time2?) if min if value < min return false end end end true end value = Time2.new(123) constraint = Constraints::Range.new(Time2.new(45)) validate(value, constraint) CRYSTAL end it "casts from virtual to single type" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class CastSpecFoo end class CastSpecBar < CastSpecFoo def bar 1 end end class CastSpecBaz < CastSpecBar end a = CastSpecBar.new || CastSpecFoo.new || CastSpecBaz.new b = a.as(CastSpecBar) b.bar CRYSTAL end it "casts from virtual to single type raises TypeCastError" do run(<<-CRYSTAL).to_b.should be_true require "prelude" class CastSpecFoo end class CastSpecBar < CastSpecFoo def bar 1 end end class CastSpecBaz < CastSpecBar end a = CastSpecBar.new || CastSpecFoo.new || CastSpecBaz.new begin a.as(CastSpecBaz) false rescue ex ex.message.not_nil!.includes?("Cast from CastSpecBar to CastSpecBaz failed") && (ex.class == TypeCastError) end CRYSTAL end it "casts from pointer to pointer" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 1_i64 pointerof(a).as(Int32*).value CRYSTAL end it "casts to module" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" module CastSpecMoo def moo 2 end end class CastSpecFoo end class CastSpecBar < CastSpecFoo include CastSpecMoo def bar 1 end end class CastSpecBaz < CastSpecBar end class CastSpecBan < CastSpecFoo include CastSpecMoo end a = CastSpecBar.new || CastSpecFoo.new || CastSpecBaz.new || CastSpecBan.new m = a.as(CastSpecMoo) m.moo CRYSTAL end it "casts from nilable to nil" do run(<<-CRYSTAL).to_b.should be_true require "prelude" a = 1 == 2 ? Reference.new : nil c = a.as(Nil) c == nil CRYSTAL end it "casts from nilable to nil raises TypeCastError" do run(<<-CRYSTAL).to_b.should be_true require "prelude" a = 1 == 1 ? Reference.new : nil begin a.as(Nil) false rescue ex ex.message.not_nil!.includes?("Cast from Reference to Nil failed") && (ex.class == TypeCastError) end CRYSTAL end it "casts to base class making it virtual" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 1.5 end end bar = Bar.new x = bar.as(Foo).foo x.to_i! CRYSTAL end it "casts to bigger union" do run(<<-CRYSTAL).to_i.should eq(1) x = 1.5.as(Int32 | Float64) x.to_i! CRYSTAL end it "allows casting nil to Void*" do run(<<-CRYSTAL).to_i.should eq(0) nil.as(Void*).address CRYSTAL end it "allows casting nilable type to Void* (1)" do run(<<-CRYSTAL).to_i.should_not eq(0) a = 1 == 1 ? Reference.new : nil a.as(Void*).address CRYSTAL end it "allows casting nilable type to Void* (2)" do run(<<-CRYSTAL).to_i.should eq(0) a = 1 == 2 ? Reference.new : nil a.as(Void*).address CRYSTAL end it "allows casting nilable type to Void* (3)" do run(<<-CRYSTAL).to_i.should_not eq(0) class Foo end a = 1 == 1 ? Reference.new : (1 == 2 ? Foo.new : nil) a.as(Void*).address CRYSTAL end it "casts (bug)" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" (1 || 1.1).as(Int32) 123 CRYSTAL end it "can cast from Void* to virtual type (#3014)" do run(<<-CRYSTAL).to_i.should eq(42) abstract class Foo abstract def hi end class Bar < Foo def hi 42 end end Bar.new.as(Void*).as(Foo).hi CRYSTAL end it "upcasts from non-generic to generic" do run(<<-CRYSTAL).to_i.should eq(2) class Foo(T) def foo 1 end end class Bar < Foo(Int32) def foo 2 end end Bar.new.as(Foo(Int32)).foo CRYSTAL end it "upcasts type to virtual (#3304)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 2 end end Foo.new.as(Foo).foo CRYSTAL end it "upcasts type to virtual (2) (#3304)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 2 end end class Gen(T) def self.cast(x) x.as(T) end end Gen(Foo).cast(Foo.new).foo CRYSTAL end it "casts with block var that changes type (#3341)" do codegen(<<-CRYSTAL) require "prelude" class Object def try yield self end end class Foo end x = Foo.new.as(Int32 | Foo) x.try &.as(Foo) CRYSTAL end it "casts between union types, where union has a tuple type (#3377)" do codegen(<<-CRYSTAL) require "prelude" v = 1 || true || 1.0 (v || {v}).as(Bool | Float64) CRYSTAL end it "codegens class method when type id is available but not a virtual type (#3490)" do run(<<-CRYSTAL).to_string.should eq("A") class Class def name : String {{ @type.name.stringify }} end end class Super end module Mixin end class A < Super include Mixin end class B < Super include Mixin end a = A.new.as(Super) if a.is_a?(Mixin) a.class.name else "Nope" end CRYSTAL end it "casts from nilable type to virtual type (#3512)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def foo 1 end end class Bar < Foo def foo 2 end end foo = 1 == 2 ? nil : Foo.new x = foo.as(Foo) x.foo CRYSTAL end it "can cast to metaclass (#11121)" do run(<<-CRYSTAL) class A end class B < A end A.as(A.class) CRYSTAL end it "cast virtual metaclass type to nilable virtual instance type (#12628)" do run(<<-CRYSTAL).to_b.should be_true abstract struct Base end struct Impl < Base end Base.as(Base | Base.class).as?(Base | Impl).nil? CRYSTAL end end ================================================ FILE: spec/compiler/codegen/class_spec.cr ================================================ require "../../spec_helper" describe "Code gen: class" do it "codegens call to same instance" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end def bar foo end end Foo.new.bar CRYSTAL end it "codegens instance var" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(@coco : Int32) end def coco @coco end end f = Foo.new(2) g = Foo.new(40) f.coco &+ g.coco CRYSTAL end it "codegens recursive type" do run(<<-CRYSTAL) class Foo def next=(@next : Foo) end end f = Foo.new f.next = f CRYSTAL end it "codegens method call of instance var" do run(<<-CRYSTAL).to_f64.should eq(1.0) class List def initialize @last = 0 end def foo @last = 1 @last.to_f end end l = List.new l.foo CRYSTAL end it "codegens new which calls initialize" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(value : Int32) @value = value end def value @value end end f = Foo.new 1 f.value CRYSTAL end it "codegens method from another method without obj and accesses instance vars" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo bar end def bar @a = 1 end end f = Foo.new f.foo CRYSTAL end it "codegens virtual call that calls another method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo foo2 end def foo2 1 end end class Bar < Foo end Bar.new.foo CRYSTAL end it "codegens virtual method of generic class" do run(<<-CRYSTAL).to_i.should eq(1) class Object def foo bar end def bar 'a' end end class Foo(T) def bar 1 end end Foo(Int32).new.foo.to_i! CRYSTAL end it "changes instance variable in method (ssa bug)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @var = 0 end def foo @var = 1 bar @var end def bar @var = 2 end end foo = Foo.new foo.foo CRYSTAL end # it "gets object_id of class" do # program = Program.new # program.run("Reference.object_id").to_i.should eq(program.reference.metaclass.type_id) # end it "calls method on Class class" do run(<<-CRYSTAL).to_i.should eq(1) class Class def foo 1 end end class Foo end Foo.foo CRYSTAL end it "uses number type var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo(T) def self.foo T end end Foo(1).foo CRYSTAL end it "calls class method without self" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.coco 1 end a = coco end a CRYSTAL end it "calls class method without self (2)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.coco lala end def self.lala 1 end end class Bar < Foo def self.lala 2 end a = coco end a CRYSTAL end it "assigns type to reference union type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Bar) end def x=(@x : Baz); end end class Bar; end class Baz; end f = Foo.new(Bar.new) f.x = Baz.new 1 CRYSTAL end it "does to_s for class" do run(<<-CRYSTAL).to_string.should eq("Reference") require "prelude" Reference.to_s CRYSTAL end it "allows fixing an instance variable's type" do run(<<-CRYSTAL).to_b.should be_true class Foo @x : Bool def initialize(@x) end def x @x end end Foo.new(true).x CRYSTAL end it "codegens initialize with instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x : Nil def initialize @x end end Foo.new 1 CRYSTAL end it "reads other instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end end foo = Foo.new(1) foo.@x CRYSTAL end it "reads a virtual type instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end end class Bar < Foo end foo = Foo.new(1) || Bar.new(2) foo.@x CRYSTAL end it "reads a union type instance var (reference union, first type)" do run(<<-CRYSTAL).to_i.should eq(10) class Foo def initialize(@x : Int32) end def x @x end end class Bar def initialize(@y : Int32, @x : Bool) end def x @x end end foo = Foo.new(10) bar = Bar.new(2, true) union = foo || bar var = union.@x if var.is_a?(Int32) var else 20 end CRYSTAL end it "reads a union type instance var (reference union, second type)" do run(<<-CRYSTAL).to_i.should eq('a'.ord) class Foo def initialize(@x : Int32) end def x @x end end class Bar def initialize(@y : Int32, @x : Char) end def x @x end end foo = Foo.new(10) bar = Bar.new(2, 'a') union = bar || foo var = union.@x if var.is_a?(Char) var else 'b' end CRYSTAL end it "reads a union type instance var (mixed union, first type)" do run(<<-CRYSTAL).to_i.should eq(10) struct Foo def initialize(@x : Int32) end def x @x end end class Bar def initialize(@y : Int32, @x : Bool) end def x @x end end foo = Foo.new(10) bar = Bar.new(2, true) union = foo || bar var = union.@x if var.is_a?(Int32) var else 20 end CRYSTAL end it "reads a union type instance var (mixed union, second type)" do run(<<-CRYSTAL).to_i.should eq('a'.ord) struct Foo def initialize(@x : Int32) end def x @x end end class Bar def initialize(@y : Int32, @x : Char) end def x @x end end foo = Foo.new(10) bar = Bar.new(2, 'a') union = bar || foo var = union.@x if var.is_a?(Char) var else 'b' end CRYSTAL end it "never considers read instance var as closure (#12181)" do codegen(<<-CRYSTAL) class Foo @x = 1 end def bug ->{ Foo.new.@x } end bug CRYSTAL end it "runs with nilable instance var" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil def to_i! 0 end end class Bar def initialize end def initialize(@x : Int32?) end def x @x end end bar = Bar.new bar.x.to_i! CRYSTAL end it "runs with nil instance var when inheriting" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil def to_i! 0 end end class Foo @x : Int32? def initialize(@x) end def x @x end end class Bar < Foo def initialize @x = nil end end bar = Bar.new bar.x.to_i! CRYSTAL end it "codegens bug #168" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x : Foo? def foo x = @x if x x.foo else 1 end end end class Bar < Foo def initialize(@x) end end Bar.new(Foo.new).foo CRYSTAL end it "allows initializing var with constant" do run(<<-CRYSTAL).to_i.should eq(1) class Foo A = 1 @x = A def x @x end end Foo.new.x CRYSTAL end it "codegens class method" do codegen(<<-CRYSTAL) Int32.class CRYSTAL end it "codegens virtual class method" do codegen(<<-CRYSTAL) class Foo end class Bar < Foo end (Foo.new || Bar.new).class CRYSTAL end it "allows using self in class scope" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.foo 1 end @@x = self.foo.as(Int32) def self.x @@x end end Foo.x CRYSTAL end it "allows using self in class scope" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def self.foo 1 end @@x = self.as(Foo.class) def self.x @@x end end Foo.x.foo CRYSTAL end it "makes .class always be a virtual type even if no subclasses" do codegen(<<-CRYSTAL) class Foo end p = Pointer(Foo.class).malloc(1_u64) class Bar < Foo p.value = self end CRYSTAL end it "does to_s for virtual metaclass type (1)" do run(<<-CRYSTAL).to_string.should eq("Foo") require "prelude" class Foo; end class Bar < Foo; end class Baz < Foo; end a = Foo || Bar || Baz a.to_s CRYSTAL end it "does to_s for virtual metaclass type (2)" do run(<<-CRYSTAL).to_string.should eq("Bar") require "prelude" class Foo; end class Bar < Foo; end class Baz < Foo; end a = Bar || Foo || Baz a.to_s CRYSTAL end it "does to_s for virtual metaclass type (3)" do run(<<-CRYSTAL).to_string.should eq("Baz") require "prelude" class Foo; end class Bar < Foo; end class Baz < Foo; end a = Baz || Bar || Foo a.to_s CRYSTAL end it "does not combine module metaclass types with same name but different file scopes (#15503)" do run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(11) module Foo def self.foo 1 end end alias Bar = Foo {% Bar %} # forces immediate resolution of `Bar` private module Foo def self.foo 10 end end module Baz def self.foo 100 end end def foo(x) x.foo end foo(Foo || Baz) &+ foo(Bar || Baz) CRYSTAL end it "does not combine virtual types with same name but different file scopes" do run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(101) class Foo def foo 1 end end class Bar1 < Foo def foo 10 end end alias Fred = Foo {% Fred %} # forces immediate resolution of `Foo` private class Foo def foo 100 end end private class Bar2 < Foo def foo 1000 end end Fred.new.as(Fred).foo &+ Foo.new.as(Foo).foo CRYSTAL end it "does not combine virtual metaclass types with same name but different file scopes" do run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(101) class Foo def self.foo 1 end end class Bar1 < Foo def self.foo 10 end end alias Fred = Foo {% Fred %} # forces immediate resolution of `Foo` private class Foo def self.foo 100 end end private class Bar2 < Foo def self.foo 1000 end end Fred.as(Fred.class).foo &+ Foo.as(Foo.class).foo CRYSTAL end it "does not combine generic virtual metaclass types with same name but different file scopes" do run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(11) module Foo def self.foo 1 end end alias Bar = Foo {% Bar %} # forces immediate resolution of `Bar` private module Foo def self.foo 10 end end abstract class Base end class Gen(T) < Base def self.x T.foo end end Gen(Foo).as(Base.class).x &+ Gen(Bar).as(Base.class).x CRYSTAL end it "does not combine generic module metaclass types with same name but different file scopes" do run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(11) module Foo def self.foo 1 end end alias Bar = Foo {% Bar %} # forces immediate resolution of `Bar` private module Foo def self.foo 10 end end module Gen(T) def self.x T.foo end end (Gen(Foo) || Gen(Bar)).x &+ (Gen(Bar) || Gen(Foo)).x CRYSTAL end it "builds generic class bug" do codegen(<<-CRYSTAL) abstract class Base def initialize @value = 1 end end class Foo(T) < Base @target : Nil def foo @target end end class Bar < Base def foo end end ex = Foo(Int32).new || Bar.new ex.foo CRYSTAL end it "resolves type declaration when accessing instance var (#348)" do codegen(<<-CRYSTAL) require "prelude" lib LibC type Foo = Int64[8] end class Bar def initialize @foo = uninitialized LibC::Foo end end Bar.new.inspect CRYSTAL end it "gets class of virtual type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end class Bar < Foo def self.foo 2 end end f = Bar.new || Foo.new f.class.foo CRYSTAL end it "notifies superclass recursively on inheritance (#576)" do run(<<-CRYSTAL).to_string.should eq("Qux") class Class def name : String {{ @type.name.stringify }} end def foo name end end class Foo end ptr = Pointer(Foo.class).malloc(1_u64) ptr.value = Foo ptr.value.foo class Bar < Foo; end ptr.value = Bar ptr.value.foo class Baz < Bar; end ptr.value = Baz ptr.value.foo class Qux < Baz; end ptr.value = Qux ptr.value.foo CRYSTAL end it "works with array in variable initializer in non-generic type (#855)" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" class Foo @ary = [1, 2, 3] def sum @ary.sum end end Foo.new.sum CRYSTAL end it "works with array in variable initializer in generic type (#855)" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" class Foo(T) @ary = [1, 2, 3] def sum @ary.sum end end Foo(Int32).new.sum CRYSTAL end it "doesn't crash on instance variable assigned a proc, and never instantiated (#923)" do codegen(<<-CRYSTAL) class Klass def self.f(arg) end @a : Proc(String, Nil) = ->f(String) end CRYSTAL end it "does to_s on class" do run(<<-CRYSTAL).to_string.should eq("Class") require "prelude" class Foo end Foo.class.to_s CRYSTAL end it "invokes class method inside instance method (#1119)" do run(<<-CRYSTAL).to_i.should eq(123) class Class def bar 123 end end class Foo def test Foo.class end end x = Foo.new.test x.bar CRYSTAL end it "codegens method of class union including Int (#1476)" do run(<<-CRYSTAL).to_i.should eq(1) class Class def foo 1 end end x = Int || Int32 x.foo CRYSTAL end it "can use a Main class (#1628)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Main def self.foo 1 end end Main.foo CRYSTAL end it "codegens singleton (#718)" do run(<<-CRYSTAL).to_string.should eq("Hello") class Singleton @@instance = new def initialize @msg = "Hello" end def msg @msg end def self.get_instance @@instance end end Singleton.get_instance.msg CRYSTAL end it "doesn't crash if not using undefined instance variable in superclass" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(@x) end def x @x end end class Bar < Foo def initialize(@x : Int32) end end foo = Bar.new(42) foo.x CRYSTAL end it "codegens virtual metaclass union bug (#2597)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end class Foo1 < Foo def self.foo 2 end end class Foo2 < Foo def self.foo 3 end end class Bar @foo : Foo.class def initialize @foo = if 1 == 1 Foo1 elsif 1 == 2 Foo2 else Foo end end def foo @foo end end Bar.new.foo.foo CRYSTAL end it "doesn't crash on #1216" do codegen(<<-CRYSTAL) class Foo def initialize(@ivar : Int32) meth end def meth r = self.class.new(5) r.@ivar end end Foo.new(6) CRYSTAL end it "doesn't crash on #1216 with pointerof" do codegen(<<-CRYSTAL) class Foo def initialize(@ivar : Int32) meth end def meth r = self.class.new(5) pointerof(r.@ivar) end end Foo.new(6) CRYSTAL end it "doesn't crash on #1216 (reduced)" do codegen(<<-CRYSTAL) class Foo def foo crash.foo end end def crash x = Foo.allocate x.foo x end crash CRYSTAL end it "doesn't crash on abstract class never instantiated (#2840)" do codegen(<<-CRYSTAL) require "prelude" abstract class Foo end if 1 == 2 true else Pointer(Foo).malloc(1_u64).value.foo end CRYSTAL end it "can assign virtual metaclass to virtual metaclass (#3007)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end class Bar < Foo def self.foo 2 end end class Baz < Bar def self.foo 3 end end class Gen(T) def initialize(x : T) end end ptr = Pointer(Foo.class).malloc(1_u64) ptr.value = Bar || Baz ptr.value.foo CRYSTAL end it "transfers initializer from module to generic class" do run(<<-CRYSTAL).to_i.should eq(123) module Moo @x = 123 def x @x end end class Foo(T) include Moo end Foo(Int32).new.x CRYSTAL end it "transfers initializer from generic module to non-generic class" do run(<<-CRYSTAL).to_i.should eq(123) module Moo(T) @x = 123 def x @x end end class Foo include Moo(Int32) end Foo.new.x CRYSTAL end it "transfers initializer from generic module to generic class" do run(<<-CRYSTAL).to_i.should eq(123) module Moo(T) @x = 123 def x @x end end class Foo(T) include Moo(T) end Foo(Int32).new.x CRYSTAL end it "doesn't skip false initializers (#3272)" do run(<<-CRYSTAL).to_i.should eq(20) class Parent @foo = true def foo @foo end end class Child < Parent @foo = false end Child.new.foo ? 10 : 20 CRYSTAL end it "doesn't skip zero initializers (#3272)" do run(<<-CRYSTAL).to_i.should eq(0) class Parent @foo = 123 def foo @foo end end class Child < Parent @foo = 0 end Child.new.foo CRYSTAL end it "codegens virtual generic class instance metaclass (#3819)" do run(<<-CRYSTAL).to_string.should eq("Foo") module Core end class Base(T) include Core end class Foo < Base(String) end class Bar < Base(Int32) end class Class def name : String {{ @type.name.stringify }} end end Foo.new.as(Core).class.name CRYSTAL end it "codegens class with recursive tuple to class (#4520)" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(1) class Foo @foo : {Foo, Foo}? def initialize(@x : Int32) end def foo=(@foo) end def x @x end end foo = Foo.new(1) foo.foo = {Foo.new(2), Foo.new(3)} foo.x CRYSTAL end it "runs instance variable initializer at the class level" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 = bar def self.bar 42 end def x @x end end Foo.new.x CRYSTAL end it "runs instance variable initializer at the class level, for generic type" do run(<<-CRYSTAL).to_i.should eq(42) class Foo(T) @x : T = bar def self.bar 42 end def x @x end end Foo(Int32).new.x CRYSTAL end pending "codegens assignment of generic metaclasses (1) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(T)") class Class def name : String {{ @type.name.stringify }} end end class Foo(T); end class Bar(T) < Foo(T); end x = Foo x = Bar x.name CRYSTAL end pending "codegens assignment of generic metaclasses (2) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(Int32)") class Class def name : String {{ @type.name.stringify }} end end class Foo(T); end class Bar(T) < Foo(T); end x = Foo x = Bar(Int32) x.name CRYSTAL end it "codegens assignment of generic metaclasses (3) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(Int32)") class Class def name : String {{ @type.name.stringify }} end end class Foo(T); end class Bar(T) < Foo(T); end x = Foo(Int32) x = Bar(Int32) x.name CRYSTAL end it "codegens assignment of generic metaclasses (4) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(Int32)") class Class def name : String {{ @type.name.stringify }} end end class Foo(T); end class Bar(T) < Foo(T); end x = Foo(String) x = Bar(Int32) x.name CRYSTAL end it "codegens assignment of generic metaclasses, base is non-generic (1) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(T)") class Class def name : String {{ @type.name.stringify }} end end class Foo; end class Bar(T) < Foo; end x = Foo x = Bar x.name CRYSTAL end it "codegens assignment of generic metaclasses, base is non-generic (2) (#10394)" do run(<<-CRYSTAL).to_string.should eq("Bar(Int32)") class Class def name : String {{ @type.name.stringify }} end end class Foo; end class Bar(T) < Foo; end x = Foo x = Bar(Int32) x.name CRYSTAL end end ================================================ FILE: spec/compiler/codegen/class_var_spec.cr ================================================ require "../../spec_helper" describe "Codegen: class var" do it "codegens class var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @@foo = 1 def self.foo @@foo end end Foo.foo CRYSTAL end it "codegens class var as nil" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil; def to_i; 0; end; end class Foo @@foo = nil def self.foo @@foo end end Foo.foo.to_i CRYSTAL end it "codegens class var inside instance method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @@foo = 1 def foo @@foo end end Foo.new.foo CRYSTAL end it "codegens class var as nil if assigned for the first time inside method" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil; def to_i!; 0; end; end class Foo def self.foo @@foo = 1 @@foo end end Foo.foo.to_i! CRYSTAL end it "codegens class var inside module" do run(<<-CRYSTAL).to_i.should eq(1) module Foo @@foo = 1 def self.foo @@foo end end Foo.foo CRYSTAL end it "accesses class var from proc literal" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @@a = 1 def self.foo ->{ @@a }.call end end Foo.foo CRYSTAL end it "reads class var before initializing it (hoisting)" do run(<<-CRYSTAL).to_i.should eq(42) x = Foo.var class Foo @@var = 42 def self.var @@var end end x CRYSTAL end it "uses var in class var initializer" do run(<<-CRYSTAL).to_i.should eq(6) class Foo @@var : Int32 @@var = begin a = class_method a &+ 3 end def self.var @@var end def self.class_method 1 &+ 2 end end Foo.var CRYSTAL end it "reads simple class var before another complex one" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @@var2 : Int32 @@var2 = @@var &+ 1 @@var = 41 def self.var2 @@var2 end end Foo.var2 CRYSTAL end it "initializes class var of union with single type" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @@var : Int32 | String @@var = 42 def self.var @@var end end var = Foo.var if var.is_a?(Int32) var else 0 end CRYSTAL end it "initializes class var with array literal" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" class Foo @@var = [1, 2, 4] def self.var @@var end end Foo.var.size CRYSTAL end it "codegens second class var initializer" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @@var = 1 @@var = 2 def self.var @@var end end Foo.var CRYSTAL end it "initializes dependent constant before class var" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" def foo a = 1 b = 2 a &+ b end CONST = foo() class Foo @@foo : Int32 @@foo = CONST def self.foo @@foo end end Foo.foo CRYSTAL end it "declares and initializes" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @@x : Int32 = 42 def self.x @@x end end Foo.x CRYSTAL end it "doesn't use nilable type for initializer" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @@foo : Int32? @@foo = 42 @@bar : Int32? @@bar = @@foo def self.bar @@bar end end Foo.bar || 10 CRYSTAL end it "codegens class var with begin and vars" do run(<<-CRYSTAL).to_i.should eq(3) class Foo @@foo : Int32 @@foo = begin a = 1 b = 2 a &+ b end def self.foo @@foo end end Foo.foo CRYSTAL end it "codegens class var with type declaration begin and vars" do run(<<-CRYSTAL).to_i.should eq(3) class Foo @@foo : Int32 = begin a = 1 b = 2 a &+ b end def self.foo @@foo end end Foo.foo CRYSTAL end it "codegens class var with nilable reference type" do run(<<-CRYSTAL).to_string.should eq("hello") class Foo @@foo : String? = nil def self.foo @@foo ||= "hello" end end Foo.foo CRYSTAL end it "initializes class var the moment it reaches it" do run(<<-CRYSTAL).to_string.should eq("BAR") require "prelude" ENV["FOO"] = "BAR" class Foo @@x = ENV["FOO"] def self.x @@x end end w = Foo.x z = Foo.x z CRYSTAL end it "gets pointerof class var" do run(<<-CRYSTAL).to_i.should eq(10) z = Foo.foo class Foo @@foo = 10 def self.foo pointerof(@@foo).value end end z CRYSTAL end it "gets pointerof class var complex constant" do run(<<-CRYSTAL).to_i.should eq(10) z = Foo.foo class Foo @@foo : Int32 @@foo = begin a = 10 a end def self.foo pointerof(@@foo).value end end z CRYSTAL end it "doesn't inherit class var value in subclass" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @@var = 1 def self.var @@var end def self.var=(@@var) end end class Bar < Foo end Foo.var = 2 Bar.var CRYSTAL end it "doesn't inherit class var value in module" do run(<<-CRYSTAL).to_i.should eq(1) module Moo @@var = 1 def var @@var end def self.var=(@@var) end end class Foo include Moo end Moo.var = 2 Foo.new.var CRYSTAL end it "reads class var from virtual type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @@var = 1 def self.var=(@@var) end def self.var @@var end def var @@var end end class Bar < Foo end Bar.var = 2 ptr = Pointer(Foo).malloc(1_u64) ptr.value = Bar.new ptr.value.var CRYSTAL end it "reads class var from virtual type metaclass" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @@var = 1 def self.var=(@@var) end def self.var @@var end end class Bar < Foo end Bar.var = 2 ptr = Pointer(Foo.class).malloc(1_u64) ptr.value = Bar ptr.value.var CRYSTAL end it "writes class var from virtual type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @@var = 1 def self.var=(@@var) end def self.var @@var end def var=(@@var) end end class Bar < Foo end ptr = Pointer(Foo).malloc(1_u64) ptr.value = Bar.new ptr.value.var = 2 Bar.var CRYSTAL end it "declares var as uninitialized and initializes it unsafely" do run(<<-CRYSTAL).to_i.should eq(10) class Foo @@x = uninitialized Int32 @@x = Foo.bar def self.bar if 1 == 2 @@x else 10 end end def self.x @@x end end Foo.x CRYSTAL end it "doesn't crash with pointerof from another module" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo @@x : Int32? @@x = 1 def self.x pointerof(@@x).value end end class Bar def self.bar Foo.x end end Bar.bar CRYSTAL end it "codegens generic class with class var" do run(<<-CRYSTAL).to_i.should eq(1 + 1 + 10 + 20) class Foo(T) @@bar = 1 def bar @@bar end def bar=(@@bar) end end f1 = Foo(Int32).new f2 = Foo(String).new a = f1.bar b = f2.bar f1.bar = 10 c = f2.bar f2.bar = 20 d = f1.bar a &+ b &+ c &+ d CRYSTAL end it "inline initialization of simple class var" do mod = codegen(<<-CRYSTAL) class Foo @@x = 1 end CRYSTAL mod.to_s.should_not contain("x:init") end it "doesn't error if class var shares name with const (#7865)" do run(<<-CRYSTAL).to_string.should eq("asdfgh") require "prelude" class Pattern @@A = "asdf" A = "\#{@@A}gh" end Pattern::A CRYSTAL end it "catch infinite loop in class var initializer" do run(<<-CRYSTAL).to_string.should eq("error: Recursion while initializing class variables and/or constants") require "prelude" module Crystal def self.main_user_code(argc : Int32, argv : UInt8**) LibCrystalMain.__crystal_main(argc, argv) rescue ex print "error: \#{ex.message}" end end class Foo @@x : Int32 = init def self.init @@x + 1 end def self.x @@x end end nil CRYSTAL end it "runs class var side effects (#8862)" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" class Foo @@x = 0 def self.set @@x = 3 end def self.x @@x end end a = Hello.value class Hello @@value : Int32 = begin Foo.set 1 &+ 2 end def self.value @@value end end a &+ Foo.x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/closure_spec.cr ================================================ require "../../spec_helper" describe "Code gen: closure" do it "codegens simple closure at global scope" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 foo = ->{ a } foo.call CRYSTAL end it "codegens simple closure in function" do run(<<-CRYSTAL).to_i.should eq(1) def foo a = 1 ->{ a } end foo.call CRYSTAL end it "codegens simple closure in function with argument" do run(<<-CRYSTAL).to_i.should eq(1) def foo(a) ->{ a } end foo(1).call CRYSTAL end it "codegens simple closure in block" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end f = foo do x = 1 -> { x } end f.call CRYSTAL end it "codegens closured nested in block" do run(<<-CRYSTAL).to_i.should eq(3) def foo yield end a = 1 f = foo do b = 2 -> { a &+ b } end f.call CRYSTAL end it "codegens closured nested in block with a call with a closure with same names" do run(<<-CRYSTAL).to_i.should eq(4) def foo a = 3 f = -> { a } yield f.call end a = 1 f = foo do |x| -> { a &+ x } end f.call CRYSTAL end it "codegens closure with block that declares same var" do run(<<-CRYSTAL).to_i.should eq(3) def foo a = 1 yield a end f = foo do |x| a = 2 -> { a &+ x } end f.call CRYSTAL end it "codegens closure with def that has an if" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield 1 if 1 yield 2 end f = foo do |x| -> { x } end f.call CRYSTAL end it "codegens multiple nested blocks" do run(<<-CRYSTAL).to_i.should eq(9) def foo yield 1 yield 2 yield 3 end a = 1 f = foo do |x| b = 1 foo do |y| c = 1 -> { a &+ b &+ c &+ x &+ y } end end f.call CRYSTAL end it "codegens closure with nested context without new closured vars" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end a = 1 f = foo do -> { a } end f.call CRYSTAL end it "codegens closure with nested context without new closured vars" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield end def bar yield end a = 1 f = foo do b = 1 bar do -> { a &+ b } end end f.call CRYSTAL end it "codegens closure with nested context without new closured vars but with block arg" do run(<<-CRYSTAL).to_i.should eq(2) def foo yield end def bar yield 3 end a = 1 f = foo do b = 1 bar do |x| x -> { a &+ b } end end f.call CRYSTAL end it "unifies types of closured var" do run(<<-CRYSTAL).to_i.should eq(2) a = 1 f = -> { a } a = 2.5 f.call.to_i! CRYSTAL end it "codegens closure with block" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end a = 1 ->{ foo { a } }.call CRYSTAL end it "codegens closure with self and var" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(@x : Int32) end def foo a = 2 ->{ self.x &+ a } end def x @x end end Foo.new(1).foo.call CRYSTAL end it "codegens closure with implicit self and var" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(@x : Int32) end def foo a = 2 ->{ x &+ a } end def x @x end end Foo.new(1).foo.call CRYSTAL end it "codegens closure with instance var and var" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(@x : Int32) end def foo a = 2 ->{ @x &+ a } end end Foo.new(1).foo.call CRYSTAL end it "codegens closure with instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end def foo ->{ @x } end end Foo.new(1).foo.call CRYSTAL end it "codegens closure with instance var and block" do run(<<-CRYSTAL).to_i.should eq(3) def bar yield end class Foo def initialize(@x : Int32) end def foo bar do a = 2 ->{ @x &+ a } end end end Foo.new(1).foo.call CRYSTAL end it "codegen closure in instance method without self closured" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo ->(a : Int32) { a } end end Foo.new.foo.call(1) CRYSTAL end it "codegens closure inside initialize inside block with self" do run(<<-CRYSTAL) def foo yield end class Foo def initialize -> { self } end end foo do Foo.new end CRYSTAL end it "doesn't free closure memory (bug)" do run(<<-CRYSTAL).to_i.should eq(1249975000_i64) require "prelude" def foo i = 0 while i < 50_000 yield i i += 1 end end funcs = [] of -> Int32 foo do |x| funcs.push(->{ x }) end a = 0_i64 funcs.each do |func| a += func.call end a CRYSTAL end it "codegens nested closure" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 ->{ ->{ a } }.call.call CRYSTAL end it "codegens super nested closure" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 ->{ ->{ -> { -> { a } } } }.call.call.call.call CRYSTAL end it "codegens nested closure with block (1)" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end a = 1 ->{ foo { ->{ a } } }.call.call CRYSTAL end it "codegens nested closure with block (2)" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end a = 1 ->{ ->{ foo { a } } }.call.call CRYSTAL end it "codegens nested closure with nested closured variable" do run(<<-CRYSTAL).to_i.should eq(3) a = 1 ->{ b = 2 ->{ a &+ b } }.call.call CRYSTAL end it "codegens super nested closure with nested closured variable" do run(<<-CRYSTAL).to_i.should eq(10) def foo yield 4 end a = 1 ->{ b = 2 ->{ -> { -> { c = 3 foo do |d| -> { a &+ b &+ c &+ d } end } } } }.call.call.call.call.call CRYSTAL end it "codegens proc literal with struct" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def initialize(@x : Int32) end def x @x end end f = ->(foo : Foo) { foo.x } obj = Foo.new(2) f.call(obj) CRYSTAL end it "codegens closure with struct" do run(<<-CRYSTAL).to_i.should eq(3) struct Foo def initialize(@x : Int32) end def x @x end end a = 1 f = ->(foo : Foo) { foo.x &+ a } obj = Foo.new(2) f.call(obj) CRYSTAL end it "codegens closure with self and arguments" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(@x : Int32) end def foo(x) @x &+ x end def bar ->foo(Int32) end end f = Foo.new(1).bar f.call(2) CRYSTAL end it "codegens nested closure that mentions var in both contexts" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 f = ->{ a -> { a } } f.call.call CRYSTAL end it "transforms block to proc literal" do run(<<-CRYSTAL).to_i.should eq(2) def foo(&block : Int32 -> Int32) block.call(1) end a = 1 foo do |x| x &+ a end CRYSTAL end it "transforms block to proc literal with free var" do run(<<-CRYSTAL).to_i.should eq(10) def foo(&block : Int32 -> U) forall U block end a = 1 g = foo { |x| x &+ a } h = foo { |x| x.to_f + a } (g.call(3) + h.call(5)).to_i! CRYSTAL end it "allows passing block as proc literal to new and to initialize" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize(&block : Int32 -> Float64) @block = block end def block @block end end a = 1 foo = Foo.new { |x| x.to_f! + a } foo.block.call(1).to_i! CRYSTAL end it "allows giving less block args when transforming block to proc literal" do run(<<-CRYSTAL).to_i.should eq(2) def foo(&block : Int32 -> U) forall U block.call(1) end a = 1 v = foo do 1.5 + a end v.to_i! CRYSTAL end it "allows passing proc literal to def that captures block with &" do run(<<-CRYSTAL).to_i.should eq(2) def foo(&block : Int32 -> Int32) block.call(1) end a = 1 f = ->(x : Int32) { x &+ a } foo &f CRYSTAL end it "allows mixing yield and block.call" do run(<<-CRYSTAL).to_i.should eq(3) def foo(&block : Int32 ->) yield 1 block.call 2 end a = 0 foo { |x| a &+= x } a CRYSTAL end it "closures struct self" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def foo ->{ @x } end end Foo.new(1).foo.call CRYSTAL end it "doesn't form a closure if invoking class method" do run(<<-CRYSTAL).to_b.should be_false require "prelude" class Foo def self.foo ->{ bar }.closure? end def self.bar end end Foo.foo CRYSTAL end it "doesn't form a closure if invoking class method with self" do run(<<-CRYSTAL).to_b.should be_false require "prelude" class Foo def self.foo ->{ self.bar }.closure? end def self.bar end end Foo.foo CRYSTAL end it "captures block and accesses local variable (#2050)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def capture(&block) block end coco = 1 capture do coco end coco CRYSTAL end it "codegens closured self in block (#3388)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(@x : Int32) end def x @x end def foo yield ->{ self } end end foo = Foo.new(42) foo2 = foo.foo { } foo2.call.x CRYSTAL end it "doesn't incorrectly consider local as closured (#4948)" do codegen(<<-CRYSTAL) arg = 1 f1 = ->{ # Here 'local' isn't to be confused with # the outer closured 'local' local = 1 local &+ arg } arg = 2 local = 4_i64 f2 = ->{ local.to_i! } f1.call &+ f2.call CRYSTAL end it "ensures it can raise from the closure check" do expect_raises(Exception, "::raise must be of NoReturn return type!") do codegen(<<-CRYSTAL) def raise(m : String) end fun a(a : -> Int32) end value = 1 p = ->{ value } a(p) CRYSTAL end end it "allows passing an external function along" do codegen(<<-CRYSTAL) require "prelude" lib LibA fun a(a : Void* -> Void*) end fun b(a : Void* -> Void*) LibA.a(a) end CRYSTAL end it "allows passing an external function along (2)" do codegen(<<-CRYSTAL) lib LibFoo struct S callback : -> end end s = LibFoo::S.new s.callback = nil CRYSTAL end it "uses atomic allocation for closure data if closured variables have no inner pointers" do run(<<-CRYSTAL, Nil) fun __crystal_malloc64(size : UInt64) : Void* Pointer(Void).new(0_u64) end struct Foo @a = 1.2 @b = true end x = 0 y = Foo.new -> { {x, y} } nil CRYSTAL end it "uses non-atomic allocation for closure data if closured variables contain inner pointers" do run(<<-CRYSTAL, Nil) fun __crystal_malloc_atomic64(size : UInt64) : Void* Pointer(Void).new(0_u64) end class Foo @x : Foo? def foo -> { @x } end end x = Foo.new -> { x } y = Pointer(Void).new(0_u64) -> { y } x.foo nil CRYSTAL end it "uses non-atomic allocation for nested closure data" do # nested closures always contain a pointer to their parent closures run(<<-CRYSTAL, Bool).should be_false module Closure @@atomic = uninitialized Int32 def self.atomic pointerof(@@atomic).as(Void*) end end fun __crystal_malloc_atomic64(size : UInt64) : Void* Closure.atomic end struct Proc def closure_data func = self ptr = pointerof(func).as({Void*, Void*}*) ptr.value[1] end end x = 0 fn = -> do y = 0 -> { x &+ y } end fn.call.closure_data.address == Closure.atomic.address CRYSTAL end end ================================================ FILE: spec/compiler/codegen/const_spec.cr ================================================ require "../../spec_helper" describe "Codegen: const" do it "define a constant" do run("CONST = 1; CONST").to_i.should eq(1) end it "support nested constant" do run("class Foo; A = 1; end; Foo::A").to_i.should eq(1) end it "support constant inside a def" do run(<<-CRYSTAL).to_i.should eq(1) class Foo A = 1 def foo A end end Foo.new.foo CRYSTAL end it "finds nearest constant first" do run(<<-CRYSTAL).to_f32.should eq(2.5) CONST = 1 class Foo CONST = 2.5_f32 def foo CONST end end Foo.new.foo CRYSTAL end it "allows constants with same name" do run(<<-CRYSTAL).to_f32.should eq(2.5) CONST = 1 class Foo CONST = 2.5_f32 def foo CONST end end CONST Foo.new.foo CRYSTAL end it "constants with expression" do run(<<-CRYSTAL).to_i.should eq(2) CONST = 1 + 1 CONST CRYSTAL end it "finds global constant" do run(<<-CRYSTAL).to_i.should eq(1) CONST = 1 class Foo def foo CONST end end Foo.new.foo CRYSTAL end it "define a constant in lib" do run("lib LibFoo; A = 1; end; LibFoo::A").to_i.should eq(1) end it "invokes block in const" do run("require \"prelude\"; CONST = [\"1\"].map { |x| x.to_i }; CONST[0]").to_i.should eq(1) end it "declare constants in right order" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" CONST1 = 1 + 1 CONST2 = true ? CONST1 : 0 CONST2 CRYSTAL end it "uses correct types lookup" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Moo class B def foo 1 end end C = B.new; end def foo Moo::C.foo end foo CRYSTAL end it "codegens variable assignment in const" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def initialize(@x : Int32) end def x @x end end CONST = begin f = Foo.new(1) f end def foo CONST.x end foo CRYSTAL end it "declaring var" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" BAR = begin a = 1 while 1 == 2 b = 2 end a end class Foo def compile BAR end end Foo.new.compile CRYSTAL end it "initialize const that might raise an exception" do run(<<-CRYSTAL).to_b.should be_true require "prelude" CONST = (raise "OH NO" if 1 == 2) def doit CONST rescue end doit.nil? CRYSTAL end it "allows implicit self in constant, called from another class (bug)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo def self.foo 1 end A = foo end class Bar def bar Foo::A end end Bar.new.bar CRYSTAL end it "codegens two consts with same variable name" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" CONST1 = begin a = 1 end CONST2 = begin a = 2.3 end (CONST1 + CONST2).to_i CRYSTAL end it "works with variable declared inside if" do run(<<-CRYSTAL).to_i.should eq(4) require "prelude" FOO = begin if 1 == 2 x = 3 else x = 4 end x end FOO CRYSTAL end it "codegens constant that refers to another constant that is a struct" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" struct Foo X = Foo.new(1) Y = X def initialize(@value : Int32) end def value @value end end Foo::Y.value CRYSTAL end it "codegens constant that is declared later because of virtual dispatch" do run(<<-CRYSTAL).to_i.should eq(1) class Base def base end end class Base2 < Base def base end end b = Base.new || Base2.new b.base class MyBase < Base CONST = 1 def base CONST end end MyBase.new.base CRYSTAL end it "doesn't crash if constant is used, but class is never instantiated (#1106)" do codegen(<<-CRYSTAL) require "prelude" class Foo BAR = 1 || 2 def foo BAR end end ->(x : Foo) { x.foo } CRYSTAL end it "uses const before declaring it (hoisting)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" x = CONST CONST = foo def foo a = 1 b = 2 a &+ b end x CRYSTAL end it "uses const before declaring it in another module" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" def foo a = 1 b = 2 a + b end class Foo def self.foo CONST end end x = Foo.foo CONST = foo x CRYSTAL end it "initializes simple const" do run(<<-CRYSTAL).to_i.should eq(10) FOO = 10 FOO CRYSTAL end it "initializes simple const via another const" do run(<<-CRYSTAL).to_i.should eq(10) BAR = 10 FOO = BAR FOO CRYSTAL end it "initializes ARGC_UNSAFE" do run(<<-CRYSTAL).to_i.should eq(0) ARGC_UNSAFE CRYSTAL end it "gets pointerof constant" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" z = pointerof(FOO).value FOO = 10 z CRYSTAL end it "gets pointerof complex constant" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" z = pointerof(FOO).value FOO = begin a = 10 a end z CRYSTAL end it "gets pointerof constant inside class" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" class Foo BAR = 42 @z : Int32 def initialize @z = pointerof(BAR).value end def z @z end end Foo.new.z CRYSTAL end it "inlines simple const" do mod = codegen(<<-CRYSTAL) CONST = 1 CONST CRYSTAL mod.to_s.should_not contain("CONST") end it "inlines enum value" do mod = codegen(<<-CRYSTAL) enum Foo CONST end Foo::CONST CRYSTAL mod.to_s.should_not contain("CONST") end it "inlines const with math" do mod = codegen(<<-CRYSTAL) struct Int32 def //(other) self end end CONST = (((1 + 2) * 3 &+ 1 &* 3 &- 2) // 2) + 42000 CONST CRYSTAL mod.to_s.should_not contain("CONST") mod.to_s.should contain("42005") end it "inlines const referencing another const" do mod = codegen(<<-CRYSTAL) OTHER = 1 CONST = OTHER CONST CRYSTAL mod.to_s.should_not contain("CONST") mod.to_s.should_not contain("OTHER") end it "inlines bool const" do mod = codegen(<<-CRYSTAL) CONST = true CONST CRYSTAL mod.to_s.should_not contain("CONST") end it "inlines char const" do mod = codegen(<<-CRYSTAL) CONST = 'a' CONST CRYSTAL mod.to_s.should_not contain("CONST") end it "synchronizes initialization of constants" do run(<<-CRYSTAL).to_b.should be_true require "prelude" def foo v1, v2 = 1, 1 rand(100000..10000000).times do v1, v2 = v2, v1 &+ v2 end v2 end ch = Channel(Int32).new 10.times do spawn do ch.send X end end X = foo def test(ch) expected = X 10.times do if ch.receive != expected return false end end true end test(ch) CRYSTAL end it "runs const side effects (#8862)" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" class Foo @@x = 0 def self.set @@x = 3 end def self.x @@x end end a = HELLO HELLO = begin Foo.set 1 &+ 2 end a &+ Foo.x CRYSTAL end it "supports closured vars inside initializers (#10474)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def bar 3 end end def func(&block : -> Int32) block.call end CONST = begin foo = Foo.new func do foo.bar end end CONST CRYSTAL end it "supports storing function returning nil" do run(<<-CRYSTAL).to_b.should be_true def foo "foo" nil end CONST = foo CONST.nil? CRYSTAL end end ================================================ FILE: spec/compiler/codegen/debug_spec.cr ================================================ require "../../spec_helper" describe "Code gen: debug" do it "codegens abstract struct (#3578)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) abstract struct Base end struct Foo < Base end struct Bar < Base end x = Foo.new || Bar.new CRYSTAL end it "codegens lib union (#7335)" do codegen <<-CRYSTAL, debug: Crystal::Debug::All lib Foo union Bar a : Int32 b : Int16 c : Int8 end end x = Foo::Bar.new CRYSTAL end it "codegens extern union (#7335)" do codegen <<-CRYSTAL, debug: Crystal::Debug::All @[Extern(union: true)] struct Foo @a = uninitialized Int32 @b = uninitialized Int16 @c = uninitialized Int8 end x = Foo.new CRYSTAL end it "inlines instance var access through getter in debug mode" do run(<<-CRYSTAL, debug: Crystal::Debug::All, filename: "foo.cr").to_i.should eq(2) struct Bar @x = 1 def set @x = 2 end def x @x end end class Foo @bar = Bar.new def set bar.set end def bar @bar end end foo = Foo.new foo.set foo.bar.x CRYSTAL end it "codegens correct debug info for untyped expression (#4007 and #4008)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) require "prelude" int = 3 case int when 0 puts 0 when 1, 2, Int32 puts "1 | 2 | Int32" else puts int end CRYSTAL end it "codegens correct debug info for new with custom allocate (#3945)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) class Foo def initialize end def self.allocate Pointer(UInt8).malloc(1_u64).as(self) end end Foo.new CRYSTAL end it "correctly restores debug location after fun change (#4254)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) require "prelude" class Foo def self.one TWO.two { three } self end def self.three 1 + 2 end def two(&block) block end end ONE = Foo.one TWO = Foo.new ONE.three CRYSTAL end it "has correct debug location after constant initialization in call with block (#4719)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) require "prelude" fun __crystal_malloc_atomic(size : UInt32) : Void* x = uninitialized Void* x end class Foo end class Bar def initialize yield end end A = Foo.new Bar.new { } A CRYSTAL end it "has debug info in closure inside if (#5593)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) def foo if true && true yield 1 end end def bar(&block) block end foo do |i| bar do i end end CRYSTAL end it "doesn't emit incorrect debug info for closured self" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) def foo(&block : Int32 ->) block.call(1) end class Foo def bar foo do self end end end Foo.new.bar CRYSTAL end it "doesn't emit debug info for unused variable declarations (#9882)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) x : Int32 CRYSTAL end it "stores and restores debug location after jumping to main (#6920)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) require "prelude" Module.method module Module def self.value 1 &+ 2 end @@x : Int32 = value def self.method @@x end end CRYSTAL end it "stores and restores debug location after jumping to main (2)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) module Foo @@x : Int32 = begin y = 1 end def self.x @@x end end Foo.x CRYSTAL end it "stores and restores debug location after jumping to main (3)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) def raise(exception) x = uninitialized NoReturn x end lib LibFoo $foo : -> end LibFoo.foo = ->{ } CRYSTAL end it "doesn't fail on constant read calls (#11416)" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All) require "prelude" class Foo def foo end end def a_foo Foo.new end THE_FOO.foo THE_FOO = a_foo CRYSTAL end it "doesn't fail on splat expansions inside array-like literals" do run(<<-CRYSTAL, debug: Crystal::Debug::All).to_i.should eq(123) require "prelude" class Foo def each yield 1 yield 2 yield 3 end end class Bar @bar = 0 def <<(value) @bar = @bar &* 10 &+ value end def bar @bar end end x = Foo.new y = Bar{*x} y.bar CRYSTAL end {% unless LibLLVM::IS_LT_210 %} it "supports 128-bit enumerators" do codegen(<<-CRYSTAL, debug: Crystal::Debug::All).to_s.should contain(%(!DIEnumerator(name: "X", value: 1002003004005006007008009))) enum Foo : Int128 X = 1002003004005006007008009_i128 end x = Foo::X CRYSTAL end {% end %} it "doesn't fail if no top-level code follows discarded class var initializer (#15970)" do codegen <<-CRYSTAL, debug: Crystal::Debug::All module Foo @@x = 1 end CRYSTAL end it "doesn't fail if class var initializer is followed by metaclass (#15970)" do codegen <<-CRYSTAL, debug: Crystal::Debug::All module Foo @@x = 1 end Int32 CRYSTAL end it "doesn't fail if Proc self is closured (#16382)" do codegen <<-CRYSTAL, debug: Crystal::Debug::All struct Proc def partial -> do self end end end -> { }.partial.call CRYSTAL end end ================================================ FILE: spec/compiler/codegen/def_default_value_spec.cr ================================================ require "../../spec_helper" describe "Code gen: def with default value" do it "codegens def with one default value" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x = 1) x end foo CRYSTAL end it "codegens def new with one default value" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x = 1) end def x @x end end Foo.new.x CRYSTAL end it "considers first the one with more arguments" do run(<<-CRYSTAL).to_i.should eq(2) def foo(x, y = 1) 1 end def foo(x, y : String) 2 end foo 1, "hello" CRYSTAL end it "considers first the one with a restriction" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x : String, y = "") 1 end def foo(x, y) 2 end foo "hello" CRYSTAL end it "doesn't mix types of instance vars with initialize and new" do assert_type(<<-CRYSTAL) { int32 } class Foo def initialize(x = 1) @x = x end def self.new(x : String) new(1) end def x @x end end Foo.new Foo.new(1) Foo.new("hello").x CRYSTAL end it "resolves expanded call to current type, not to virtual type" do assert_type(<<-CRYSTAL) { int32 } class Foo def foo(x = 1) 2 end end class Bar < Foo def foo(x) 'a' end end bar = Bar.new bar.foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/def_spec.cr ================================================ require "../../spec_helper" describe "Code gen: def" do it "codegens empty def" do run("def foo; end; foo") end it "codegens call without args" do run("def foo; 1; end; 2; foo").to_i.should eq(1) end it "call functions defined in any order" do run("def foo; bar; end; def bar; 1; end; foo").to_i.should eq(1) end it "codegens call with args" do run("def foo(x); x; end; foo 1").to_i.should eq(1) end it "call external function 'putchar'" do run(<<-CRYSTAL).to_i.should eq(0) lib LibC fun putchar(c : Char) : Char end LibC.putchar '\\0' CRYSTAL end it "uses self" do run("struct Int; def foo; self &+ 1; end; end; 3.foo").to_i.should eq(4) end it "uses var after external" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC fun putchar(c : Char) : Char end a = 1 LibC.putchar '\\0' a CRYSTAL end it "allows to change argument values" do run("def foo(x); x = 1; x; end; foo(2)").to_i.should eq(1) end it "runs empty def" do run("def foo; end; foo") end it "builds infinite recursive function" do codegen "def foo; foo; end; foo" end it "unifies all calls to same def" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def raise(msg) nil end class Hash2 def initialize @buckets = [[1]] end def []=(key, value) bucket.push value end def [](key) bucket[0] end def bucket @buckets[0] end end hash = Hash2.new hash[1] = 2 hash[1] CRYSTAL end it "codegens recursive type with union" do run(<<-CRYSTAL) class Foo @next : Foo? def next=(n) @next = n end def next @next end end a = Foo.allocate a.next = Foo.allocate a = a.next CRYSTAL end it "codegens with related types" do run(<<-CRYSTAL) class Foo @next : Foo | Bar | Nil def next=(n) @next = n end def next @next end end class Bar @next : Foo | Bar | Nil def next=(n) @next = n end def next @next end end def foo(x, y) if n = x.next n.next = y end end a = Foo.allocate a.next = Bar.allocate foo(a, Bar.allocate) c = Foo.allocate c.next = Bar.allocate foo(c, c.next) CRYSTAL end it "codegens and doesn't break if obj is int and there's a mutation" do run(<<-CRYSTAL) require "prelude" struct Int def baz(x) end end elems = [1] elems[0].baz [1] CRYSTAL end it "codegens with and without default arguments" do run(<<-CRYSTAL).to_i.should eq(5) def foo(x = 1) x &+ 1 end foo(2) &+ foo CRYSTAL end it "codegens with and without many default arguments" do run(<<-CRYSTAL).to_i.should eq(40) def foo(x = 1, y = 2, z = 3) x &+ y &+ z end foo &+ foo(9) &+ foo(3, 4) &+ foo(6, 3, 1) CRYSTAL end it "codegens with interesting default argument" do run(<<-CRYSTAL).to_i.should eq(5) class Foo def foo(x = self.bar) x &+ 1 end def bar 1 end end f = Foo.new f.foo(2) &+ f.foo CRYSTAL end it "codegens dispatch on static method" do run(<<-CRYSTAL).to_i.should eq(1) def Object.foo(x) 1 end a = 1 a = 1.5 Object.foo(a) CRYSTAL end it "use target def type as return type" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo if false return 0 end end foo.nil? ? 1 : 0 CRYSTAL end it "codegens recursive nasty code" do codegen(<<-CRYSTAL) class Foo def initialize(x) end end class Bar def initialize(x) end end class Box @elem : Foo | Bar | Nil def set(elem) @elem = elem end def get @elem end end def foo exps = Box.new sub = foo t = Foo.new(sub) || Bar.new(sub) exps.set t exps.get || 1 end false && foo CRYSTAL end it "looks up matches in super classes and merges them with subclasses" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo(other) 1 end end class Bar < Foo def foo(other : Int) 2 end end bar1 = Bar.new bar1.foo(1 || 1.5) CRYSTAL end it "codegens def which changes type of arg" do run(<<-CRYSTAL).to_i.should eq(0) def foo(x) while x >= 0 x = -0.5 end x end foo(2).to_i! CRYSTAL end it "codegens return nil when nilable type (1)" do run(<<-CRYSTAL).to_b.should be_true def foo return if 1 == 1 Reference.new end foo.nil? CRYSTAL end it "codegens return nil when nilable type (2)" do run(<<-CRYSTAL).to_b.should be_true def foo return nil if 1 == 1 Reference.new end foo.nil? CRYSTAL end it "codegens dispatch with nilable reference union type" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil; def object_id; 0_u64; end; end class Foo; end class Bar; end f = 1 == 1 ? nil : (Foo.new || Bar.new) f.object_id CRYSTAL end it "codegens dispatch without obj, bug 1" do run(<<-CRYSTAL).to_i.should eq(2) def coco(x : Int32) 2 end def coco(x) 3 end class Foo def foo coco(1 || nil) end end Foo.new.foo CRYSTAL end it "codegens dispatch without obj, bug 1" do run(<<-CRYSTAL).to_i.should eq(2) def coco(x : Int32) 2 end def coco(x) 3 end class Foo def foo coco(1 || nil) end end class Bar < Foo end (Foo.new || Bar.new).foo CRYSTAL end it "codegens dispatch with single def when discarding unallocated ones (1)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def bar 1 end end class Bar def bar 2 end end foo = 1 == 1 ? Foo.new : Pointer(Int32).new(0_u64).as(Bar) foo.bar CRYSTAL end it "codegens dispatch with single def when discarding unallocated ones (2)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar end def something(x : Foo) 1 end def something(x : Bar) 2 end foo = 1 == 1 ? Foo.new : Pointer(Int32).new(0_u64).as(Bar) something(foo) CRYSTAL end it "codegens bug #119" do run(<<-CRYSTAL).to_b.should be_false require "prelude" x = {} of String => Hash(String, String) x.has_key?("a") CRYSTAL end it "puts union before single type in matches preferences" do run(<<-CRYSTAL).to_i.should eq(1) abstract class Foo end class Bar < Foo end class Baz < Foo end def foo(x : Foo) 2 end def foo(x : Bar | Baz) 1 end node = Baz.new || Bar.new foo(node) CRYSTAL end it "dispatches on virtual type implementing generic module (related to bug #165)" do run(<<-CRYSTAL).to_i.should eq(1) module Moo(T) def moo 1 end end abstract class Foo end class Bar < Foo include Moo(Int32) end class Baz < Foo end def method(x : Moo(Int32)) x.moo end def method(x : Baz) 2 end foo = Bar.new || Baz.new method(foo) CRYSTAL end it "fixes #230: include original owner in mangled def" do run(<<-CRYSTAL).to_b.should be_true class Base def some(other : self) false end def some(other) false end end class Foo(T) < Base def some(other : Foo) true end end a = Foo(Int32).new b = Foo(Int32).new || Foo(Int32 | Nil).new || true a.some(b) c = Foo(Int32).new c.some(c) CRYSTAL end it "doesn't crash on private def as last expression" do codegen(<<-CRYSTAL) private def foo end CRYSTAL end it "uses previous argument in default value (#1062)" do run(<<-CRYSTAL).to_i.should eq(123 * 2 + 456) def foo(x = 123, y = x &+ 456) x &+ y end foo CRYSTAL end it "can match N type argument of static array (#1203)" do run(<<-CRYSTAL).to_i.should eq(10) def fn(a : StaticArray(T, N)) forall T, N N end n = uninitialized StaticArray(Int32, 10) fn(n) CRYSTAL end it "uses dispatch call type for phi (#3529)" do codegen(<<-CRYSTAL, inject_primitives: false) def foo(x : Int32) yield 1.0 end def foo(x : Int64) yield 1.0 end foo(1 || 1_i64) do break end CRYSTAL end it "codegens union to union assignment of mutable arg (#3691)" do codegen(<<-CRYSTAL) def foo(arg) arg = "" end foo(1 || true) CRYSTAL end it "codegens yield with destructing tuple having unreachable element" do codegen(<<-CRYSTAL) def foo yield({1, while true; end}) end foo { |a, b| } CRYSTAL end end ================================================ FILE: spec/compiler/codegen/double_splat_spec.cr ================================================ require "../../spec_helper" describe "Codegen: double splat" do it "double splats named argument into arguments (1)" do run(<<-CRYSTAL).to_i.should eq(32 - 10) def foo(x, y) x &- y end tup = {x: 32, y: 10} foo **tup CRYSTAL end it "double splats named argument into arguments (2)" do run(<<-CRYSTAL).to_i.should eq(32 - 10) def foo(x, y) x &- y end tup = {y: 10, x: 32} foo **tup CRYSTAL end it "double splats named argument with positional arguments" do run(<<-CRYSTAL).to_i.should eq(1000 - 20*30) def foo(x, y, z) x &- y &* z end tup = {y: 20, z: 30} foo 1000, **tup CRYSTAL end it "double splats named argument with named args (1)" do run(<<-CRYSTAL).to_i.should eq(1000 - 20*30) def foo(x, y, z) x &- y &* z end tup = {x: 1000, z: 30} foo **tup, y: 20 CRYSTAL end it "double splats named argument with named args (2)" do run(<<-CRYSTAL).to_i.should eq(1000 - 20*30) def foo(x, y, z) x &- y &* z end tup = {z: 30} foo **tup, x: 1000, y: 20 CRYSTAL end it "double splats twice " do run(<<-CRYSTAL).to_i.should eq((1000 - 20*30) * 40) def foo(x, y, z, w) (x &- y &* z) &* w end tup1 = {x: 1000, z: 30} tup2 = {y: 20, w: 40} foo **tup2, **tup1 CRYSTAL end it "matches double splat on method with named args" do run(<<-CRYSTAL).to_i.should eq(7) def foo(**options) options[:x] &- options[:y] end foo x: 10, y: 3 CRYSTAL end it "matches double splat on method with named args and regular args" do run(<<-CRYSTAL).to_i.should eq(1000 - 20*30) def foo(x, **args) x &- args[:y] &* args[:z] end foo y: 20, z: 30, x: 1000 CRYSTAL end it "matches double splat with regular splat" do run(<<-CRYSTAL).to_i.should eq((1000 - 20*30) * 40) def foo(*args, **options) (args[0] &- args[1] &* options[:z]) &* options[:w] end foo 1000, 20, z: 30, w: 40 CRYSTAL end it "evaluates double splat argument just once (#2677)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def data Global.x &+= 1 {x: Global.x, y: Global.x, z: Global.x} end def test(x, y, z) end test(**data) Global.x CRYSTAL end it "removes literal types in all matches (#6239)" do run(<<-CRYSTAL).to_i.should eq(2) def foo(y : Float64) y.to_i! end def bar(x : Float64, **args) foo(**args) end bar(x: 1, y: 2.0) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/enum_spec.cr ================================================ require "../../spec_helper" describe "Code gen: enum" do it "codegens enum" do run(<<-CRYSTAL).to_i.should eq(1) enum Foo A = 1 end Foo::A CRYSTAL end it "codegens enum without explicit value" do run(<<-CRYSTAL).to_i.should eq(2) enum Foo A B C end Foo::C CRYSTAL end it "codegens enum value" do run(<<-CRYSTAL).to_i.should eq(1) enum Foo A = 1 end Foo::A.value CRYSTAL end it "creates enum from value" do run(<<-CRYSTAL).to_i.should eq(1) enum Foo A B end Foo.new(1).value CRYSTAL end it "codegens enum bitflags (1)" do run(<<-CRYSTAL).to_i.should eq(1) @[Flags] enum Foo A end Foo::A CRYSTAL end it "codegens enum bitflags (2)" do run(<<-CRYSTAL).to_i.should eq(2) @[Flags] enum Foo A B end Foo::B CRYSTAL end it "codegens enum bitflags (4)" do run(<<-CRYSTAL).to_i.should eq(4) @[Flags] enum Foo A B C end Foo::C CRYSTAL end it "codegens enum bitflags None" do run(<<-CRYSTAL).to_i.should eq(0) @[Flags] enum Foo A end Foo::None CRYSTAL end it "codegens enum bitflags All" do run(<<-CRYSTAL).to_i.should eq(1 + 2 + 4) @[Flags] enum Foo A B C end Foo::All CRYSTAL end it "codegens enum None redefined" do run(<<-CRYSTAL).to_i.should eq(10) lib Lib @[Flags] enum Foo A None = 10 end end Lib::Foo::None CRYSTAL end it "codegens enum All redefined" do run(<<-CRYSTAL).to_i.should eq(10) lib Lib @[Flags] enum Foo A All = 10 end end Lib::Foo::All CRYSTAL end it "allows class vars in enum" do run(<<-CRYSTAL).to_i.should eq(1) enum Foo A @@class_var = 1 def self.class_var @@class_var end end Foo.class_var CRYSTAL end it "automatically defines question method for each enum member (false case)" do run(<<-CRYSTAL).to_b.should be_false struct Enum def ==(other : self) value == other.value end end enum Day SomeMonday SomeTuesday end day = Day::SomeTuesday day.some_monday? CRYSTAL end it "automatically defines question method for each enum member (true case)" do run(<<-CRYSTAL).to_b.should be_true struct Enum def ==(other : self) value == other.value end end enum Day SomeMonday SomeTuesday end day = Day::SomeTuesday day.some_tuesday? CRYSTAL end it "automatically defines question method for each enum member (flags, false case)" do run(<<-CRYSTAL).to_b.should be_false struct Enum def includes?(other : self) (value & other.value) != 0 end end @[Flags] enum Day SomeMonday SomeTuesday SomeWednesday end day = Day.new(3) day.some_wednesday? CRYSTAL end it "automatically defines question method for each enum member (flags, true case)" do run(<<-CRYSTAL).to_b.should be_true struct Enum def includes?(other : self) (value & other.value) != 0 end end @[Flags] enum Day SomeMonday SomeTuesday SomeWednesday end day = Day.new(3) day.some_tuesday? CRYSTAL end it "does ~ at compile time for enum member" do run(<<-CRYSTAL).to_i.should eq(~1) enum Foo Bar = ~1 end Foo::Bar.value CRYSTAL end it "uses enum value before declaration (hoisting)" do run(<<-CRYSTAL).to_i.should eq(1) x = Bar.bar enum Foo A = 1 end class Bar def self.bar Foo::A end end x CRYSTAL end it "casts All value to base type" do run(<<-CRYSTAL).to_i.should eq(-1073741824) @[Flags] enum Foo A = 1 << 30 B = 1 << 31 end Foo::All.value CRYSTAL end it "can use macro calls inside enum value (#424)" do run(<<-CRYSTAL).to_i.should eq(30) enum Foo macro bar 10 + 20 end A = bar end Foo::A.value CRYSTAL end it "can use macro calls inside enum value, macro defined outside enum (#424)" do run(<<-CRYSTAL).to_i.should eq(30) macro bar 10 + 20 end enum Foo A = bar end Foo::A.value CRYSTAL end it "can use macro calls inside enum value, with receiver (#424)" do run(<<-CRYSTAL).to_i.should eq(30) module Moo macro bar 10 + 20 end end enum Foo A = Moo.bar end Foo::A.value CRYSTAL end it "adds a none? method to flags enum" do run(<<-CRYSTAL).to_i.should eq(1) @[Flags] enum Foo A B end x = 0 x &+= 1 if Foo::None.none? x &+= 2 if Foo::A.none? x CRYSTAL end it "can redefine Enum.new and use previous_def" do run(<<-CRYSTAL).to_i.should eq(2) enum Foo FOO = 1 BAR = 2 def self.new(x : Int32) previous_def(2) end end Foo.new(1) CRYSTAL end it "can define flags enum : UInt64 with more than 32 values (#7268)" do run(<<-CRYSTAL).to_u64.should eq(1_u64 << 32) @[Flags] enum Foo : UInt64 #{Array.new(33) { |i| "V#{i + 1}" }.join "\n"} end Foo::V33.value CRYSTAL end it "can define flags enum : UInt128 with 128 values" do run(<<-CRYSTAL).to_u64.should eq(1_u64 << 63) @[Flags] enum Foo : UInt128 #{Array.new(128) { |i| "V#{i + 1}" }.join "\n"} end Foo::V64.value.to_u64! CRYSTAL end it "can define flags enum : UInt128 with compile-time interpreted values" do run(<<-CRYSTAL).to_u64.should eq(1 << 6) enum Foo : UInt128 A = 1_u128 << 6 B = 1_u128 << 20 C = 1_u128 << 60 end Foo::A.value.to_u64! CRYSTAL end end ================================================ FILE: spec/compiler/codegen/exception_spec.cr ================================================ require "../../spec_helper" describe "Code gen: exception" do it "codegens rescue specific leaf exception" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo < Exception end def foo raise Foo.new end def bar(x) 1 end begin foo 2 rescue ex : Foo bar(ex) end CRYSTAL end it "codegens exception handler with return" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo begin return 1 ensure 1 + 2 end end foo CRYSTAL end it "does ensure after rescue which returns (#171)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo raise "foo" rescue Global.x += 1 return ensure Global.x += 1 end foo Global.x CRYSTAL end it "executes body if nothing raised (1)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" y = 1 x = begin 2 rescue y = 10 end x + y CRYSTAL end it "executes rescue if something is raised conditionally" do run(<<-CRYSTAL).to_i.should eq(8) require "prelude" y = 1 x = 1 x = begin y == 1 ? raise("Oh no!") : nil y = 10 rescue y = 4 end x + y CRYSTAL end it "executes rescue if something is raised unconditionally" do run(<<-CRYSTAL).to_i.should eq(6) require "prelude" y = 1 x = 1 x = begin raise "Oh no!" y = 10 rescue y = 3 end x + y CRYSTAL end it "can result into union (1)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" x = begin 1 rescue 2.1 end x.to_i CRYSTAL end it "can result into union (2)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" y = begin 1 > 0 ? raise("Oh no!") : 0 rescue 2.1 end y.to_i CRYSTAL end it "handles nested exceptions" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" a = 0 b = begin begin raise "Oh no!" rescue a = 1 raise "Boom!" end rescue 2 end a + b CRYSTAL end it "executes ensure when no exception is raised (1)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" a = 0 b = begin a = 1 rescue a = 3 ensure a = 10 end a CRYSTAL end it "executes ensure when no exception is raised (2)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 0 b = begin a = 1 rescue a = 3 ensure a = 10 end b CRYSTAL end it "executes ensure when exception is raised (1)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" a = 0 b = begin a = 1 raise "Oh no!" rescue a = 3 ensure a = 2 end a CRYSTAL end it "executes ensure when exception is raised (2)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" a = 0 b = begin a = 1 raise "Oh no!" rescue a = 3 ensure a = 2 end b CRYSTAL end it "executes ensure when exception is unhandled (1)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" class Ex1 < Exception; end a = 0 b = begin begin a = 1 raise "Oh no!" rescue Ex1 a = 2 ensure a = 3 end rescue 4 end a CRYSTAL end it "executes ensure when exception is unhandled (2)" do run(<<-CRYSTAL).to_i.should eq(4) require "prelude" class Ex1 < Exception; end a = 0 b = begin begin a = 1 raise "Oh no!" rescue Ex1 a = 2 ensure a = 3 end rescue 4 end b CRYSTAL end it "ensure without rescue" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 0 begin begin raise "Oh no!" ensure a = 1 end rescue end a CRYSTAL end it "executes ensure when the main block returns" do run(<<-CRYSTAL).to_i.should eq(0) require "prelude" struct Nil; def to_i; 0; end; end def foo(x) begin return 0 if 1 == 1 ensure x.value = 1 end end x = 0 foo(pointerof(x)).to_i CRYSTAL end it "executes ensure when the main block returns" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo(x) begin return 0 if 1 == 1 ensure x.value = 1 end end x = 0 foo(pointerof(x)) x CRYSTAL end it "executes ensure when the main block yields and returns" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo2(x) begin yield ensure x.value = 1 end end def bar2(y) foo2(y) do return if 1 == 1 end end x = 0 bar2(pointerof(x)) x CRYSTAL end it "rescues with type" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end a = begin raise Ex2.new rescue Ex1 1 rescue Ex2 2 end a CRYSTAL end it "rescues with types defaults to generic rescue" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end a = begin raise "Oh no!" rescue Ex1 1 rescue Ex2 2 rescue 3 end a CRYSTAL end it "handles exception in outer block (1)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end p = 0 x = begin begin raise Ex1.new rescue Ex2 p = 1 1 end rescue 2 end x CRYSTAL end it "handles exception in outer block (2)" do run(<<-CRYSTAL).to_i.should eq(0) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end p = 0 x = begin begin raise Ex1.new rescue Ex2 p = 1 1 end rescue 2 end p CRYSTAL end it "handles subclass" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end class Ex3 < Ex1; end x = 0 begin raise Ex3.new rescue Ex1 x = 1 end x CRYSTAL end it "handle multiple exception types (1)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end x = 0 begin raise Ex2.new rescue Ex1 | Ex2 x = 1 end x CRYSTAL end it "handle multiple exception types (2)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Ex1 < Exception; end class Ex2 < Exception; end x = 0 begin raise Ex1.new rescue Ex1 | Ex2 x = 1 end x CRYSTAL end it "receives exception object" do run(<<-CRYSTAL).to_string.should eq("Ex1") require "prelude" class Ex1 < Exception def to_s(io) io << "Ex1" end end x = "" begin raise Ex1.new rescue ex x = ex.to_s end x CRYSTAL end it "executes else if no exception is raised (1)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" x = 1 y = begin rescue ex x = 2 else x = 3 end x CRYSTAL end it "executes else if no exception is raised (2)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" x = 1 y = begin rescue ex x = 2 else x = 3 end y CRYSTAL end it "doesn't execute else if exception is raised (1)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end x = 1 y = begin raise Ex1.new rescue ex x = 2 else x = 3 end x CRYSTAL end it "doesn't execute else if exception is raised (2)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end x = 1 y = begin raise Ex1.new rescue ex x = 2 else x = 3 end y CRYSTAL end it "doesn't execute else if exception is raised conditionally (1)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end x = 1 y = begin raise Ex1.new if 1 == 1 rescue ex x = 2 else x = 3 end x CRYSTAL end it "doesn't execute else if exception is raised conditionally (2)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Ex1 < Exception; end x = 1 y = begin raise Ex1.new if 1 == 1 rescue ex x = 2 else x = 3 end y CRYSTAL end it "handle exception raised by proc literal" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" x = 0 f = -> { raise "Foo" if 1 == 1 } begin f.call rescue x = 1 end x CRYSTAL end it "codegens issue #118 (1)" do codegen(<<-CRYSTAL) require "prelude" begin raise "hey" n = 3 ensure p n end CRYSTAL end it "codegens issue #118 (2)" do codegen(<<-CRYSTAL) require "prelude" n = nil begin raise "hey" n = 3 ensure p n end CRYSTAL end it "captures exception thrown from proc" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" def foo ->{ raise "OH NO" }.call end a = 1 begin foo rescue a = 2 end a CRYSTAL end it "uses exception after rescue" do run(<<-CRYSTAL).to_string.should eq("OH NO") require "prelude" begin raise "OH NO" rescue ex end ex.not_nil!.message CRYSTAL end it "doesn't codegen duplicated ensure if unreachable (#709)" do codegen(<<-CRYSTAL) require "prelude" class Foo def initialize exit if 1 == 2 end end begin begin while true end ensure Foo.new.object_id end ensure end CRYSTAL end it "executes ensure when raising inside rescue" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" a = 1 begin begin raise "OH NO" rescue raise "LALA" ensure a = 2 end rescue end a CRYSTAL end it "executes ensure of break inside while inside body" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" a = 0 while true begin break ensure a = 123 end end a CRYSTAL end it "executes ensure of break inside while inside body with nested handlers" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" a = 0 b = 0 begin while true begin break ensure a += 1 end end b = a ensure a += 1 end b CRYSTAL end it "executes ensure of break inside while inside body with block" do run(<<-CRYSTAL).to_i.should eq(0) require "prelude" class Global @@a = 0 @@b = 0 def self.a=(@@a) end def self.a @@a end def self.b=(@@b) end def self.b @@b end end def bar begin yield ensure Global.a = 1 end end bar do while true break end Global.b = Global.a end Global.b CRYSTAL end it "executes ensure of break inside while inside rescue" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" a = 0 while true begin raise "OH NO" rescue break ensure a = 123 end end a CRYSTAL end it "executes ensure of break inside while inside else" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" a = 0 while true begin rescue else break ensure a = 123 end end a CRYSTAL end it "executes ensure of next inside while inside body" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" a = 0 continue = true while continue continue = false begin next ensure a = 123 end end a CRYSTAL end it "executes return inside rescue, executing ensure" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo begin begin raise "foo" rescue Global.x += 1 return end ensure Global.x += 1 end end foo Global.x CRYSTAL end it "executes ensure from return until target" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo yield return end a = 0 begin foo {} ensure a += 1 end a CRYSTAL end it "executes ensure from return until target" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo begin yield ensure Global.x += 1 end end def bar begin foo do return end ensure Global.x += 1 end end bar Global.x CRYSTAL end it "executes ensure of next inside block" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo yield end a = 0 b = 0 begin foo do begin next ensure a += 1 end end b = a ensure a += 1 end b CRYSTAL end it "executes ensure of next inside block" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Global @@a = 0 @@b = 0 def self.a=(@@a) end def self.a @@a end def self.b=(@@b) end def self.b @@b end end def foo begin yield Global.b = Global.a ensure Global.a += 1 end end begin foo do begin next ensure Global.a += 1 end end ensure Global.a += 1 end Global.b CRYSTAL end it "executes ensure of break inside block" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def foo yield end a = 0 b = 0 begin foo do begin break ensure a += 1 end end b = a ensure a += 1 end b CRYSTAL end it "executes ensure of calling method when doing break inside block (#1233)" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo yield ensure Global.x = 123 end foo do break end Global.x CRYSTAL end it "propagates raise status (#2074)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Foo @var : Var? def method1 method2 end def method2 if var = @var var.method3 end end def var=(@var) end end class Var def method3 raise "OH NO" end end # method1 isn't marked as raise because @var's type isn't known yet Foo.new.method1 foo = Foo.new # This causes method2 to recompute, but method1 doesn't get notified # that it might now raise foo.var = Var.new a = 1 begin foo.method1 rescue ex a = 2 end a CRYSTAL end it "doesn't crash on #1988" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" begin x = 42 rescue end if x.is_a?(Int32) x else 21 end CRYSTAL end it "runs #2441" do run(<<-CRYSTAL).to_string.should eq("foo") require "prelude" while true begin raise "foo" rescue ex break end end ex.not_nil!.message.to_s CRYSTAL end it "can rescue TypeCastError (#2607)" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" begin (1 || "foo").as(String) 2 rescue e : TypeCastError 42 rescue e : Exception 0 end CRYSTAL end it "can use argument in rescue (#2844)" do run(<<-CRYSTAL).to_string.should eq("foo") require "prelude" def foo(exe) begin raise exe rescue exe exe end end ex = Exception.new("foo") ex = foo(ex) ex.message.not_nil! CRYSTAL end it "can use argument in rescue, with a different type (1) (#2844)" do run(<<-CRYSTAL).to_string.should eq("foo") require "prelude" def foo(exe) begin raise Exception.new("foo") if 1 == 1 exe rescue exe exe end end ex = foo(1).as(Exception) ex.message.not_nil! CRYSTAL end it "can use argument in rescue, with a different type (2) (#2844)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" def foo(exe) begin raise Exception.new("foo") if 1 == 2 exe rescue exe exe end end foo(10).as(Int32) CRYSTAL end it "runs NoReturn ensure (#3082)" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" begin print 1 raise "OH NO" print 0 rescue print 2 ensure print 3 exit print 4 end print 5 CRYSTAL end it "catches exception thrown by as inside method (#4030)" do run(<<-CRYSTAL).to_string.should eq("good") require "prelude" def foo a = 1 || "" a.as(String) end begin foo "bad" rescue ex : TypeCastError "good" end CRYSTAL end it "types parenthesized expression (#5511)" do run(<<-CRYSTAL).to_string.should eq("foo") require "prelude" begin ((raise "foo").bar).baz rescue ex ex.message end CRYSTAL end it "codegens return from rescue with value" do run(<<-CRYSTAL).to_i.should eq(5) require "prelude" def foo begin raise "foo" rescue return 5 end end foo CRYSTAL end it "closures rescue variable (#8141)" do codegen(<<-CRYSTAL) require "prelude" def invoke(&block) block.call end ex = nil invoke do begin rescue ex end end CRYSTAL end it "handles rescuing module type" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo; end class Ex1 < Exception include Foo end x = 0 begin raise Ex1.new rescue Foo x = 1 end x CRYSTAL end it "handles rescuing union between module type and class type" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo; end abstract class BaseError < Exception; end class Ex2 < BaseError; end class Ex1 < BaseError include Foo end x = 0 begin raise Ex1.new rescue Foo | BaseError x = 1 end x CRYSTAL end it "handles rescuing union between module types" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo; end module Bar; end class Ex1 < Exception include Foo end class Ex2 < Exception include Bar end x = 0 begin raise Ex1.new rescue Foo | Bar x = 1 end x CRYSTAL end it "does not rescue just any module" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" module Foo; end module Bar; end class Ex < Exception include Foo end x = 0 begin begin raise Ex.new("oh no") rescue Bar x = 1 end rescue ex x = 2 end x CRYSTAL end it "rescues a valid union" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo; end module Bar; end class Ex < Exception include Foo end x = 0 begin raise Ex.new("oh no") rescue Union(Foo, Bar) x = 1 end x CRYSTAL end it "rescues a valid nested union" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo; end module Bar; end module Baz; end class Ex < Exception include Foo end x = 0 begin raise Ex.new("oh no") rescue Union(Baz, Union(Foo, Bar)) x = 1 end x CRYSTAL end it "does not rescue just any union" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" module Foo; end module Bar; end module Baz; end class Ex < Exception include Foo end x = 0 begin raise Ex.new("oh no") rescue Union(Bar, Baz) x = 1 rescue x = 2 end x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/experimental_spec.cr ================================================ require "../spec_helper" describe "Code gen: experimental" do it "compiles with no argument" do run(<<-CRYSTAL).to_i.should eq(2) @[Experimental] def foo end 2 CRYSTAL end it "compiles with single string argument" do run(<<-CRYSTAL).to_i.should eq(2) @[Experimental("lorem ipsum")] def foo end 2 CRYSTAL end it "errors if invalid argument type" do assert_error <<-CRYSTAL, "first argument must be a String" @[Experimental(42)] def foo end CRYSTAL end it "errors if too many arguments" do assert_error <<-CRYSTAL, "wrong number of experimental annotation arguments (given 2, expected 1)" @[Experimental("lorem ipsum", "extra arg")] def foo end CRYSTAL end it "errors if missing link arguments" do assert_error <<-CRYSTAL, "too many named arguments (given 1, expected maximum 0)" @[Experimental(invalid: "lorem ipsum")] def foo end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/extern_spec.cr ================================================ require "../../spec_helper" describe "Codegen: extern struct" do it "declares extern struct with no constructor" do run(<<-CRYSTAL).to_i.should eq(0) @[Extern] struct Foo @x = uninitialized Int32 def x @x end end Foo.new.x CRYSTAL end it "declares extern struct with no constructor, assigns var" do run(<<-CRYSTAL).to_i.should eq(10) @[Extern] struct Foo @x = uninitialized Int32 def x=(@x) end def x @x end end foo = Foo.new foo.x = 10 foo.x CRYSTAL end it "declares extern union with no constructor" do run(<<-CRYSTAL).to_i.should eq(1069547520) @[Extern(union: true)] struct Foo @x = uninitialized Int32 @y = uninitialized Float32 def x=(@x) end def x @x end def y=(@y) end end foo = Foo.new foo.x = 1 foo.y = 1.5_f32 foo.x CRYSTAL end it "declares extern struct, sets and gets instance var" do run(<<-CRYSTAL).to_i.should eq(42) @[Extern] struct Foo @y = uninitialized Float64 @x = uninitialized Int32 def foo @x = 42 @x end end Foo.new.foo CRYSTAL end it "declares extern union, sets and gets instance var" do run(<<-CRYSTAL).to_i.should eq(1069547520) @[Extern(union: true)] struct Foo @x = uninitialized Int32 @y = uninitialized Float32 def foo @x = 1 @y = 1.5_f32 @x end end Foo.new.foo CRYSTAL end it "sets callback on extern struct" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" @[Extern] struct Foo @x = uninitialized -> Int32 def set @x = ->{ 42 } end def get @x.call end end foo = Foo.new foo.set foo.get CRYSTAL end it "sets callback on extern union" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" @[Extern(union: true)] struct Foo @y = uninitialized Float64 @x = uninitialized -> Int32 def set @x = ->{ 42 } end def get @x.call end end foo = Foo.new foo.set foo.get CRYSTAL end it "codegens extern proc call twice (#4982)" do run(<<-CRYSTAL).to_i.should eq(3) @[Extern] struct Data def initialize(@foo : Int32) end def foo @foo end end f = ->(data : Data) { data.foo } x = f.call(Data.new(1)) y = f.call(Data.new(2)) x &+ y CRYSTAL end it "codegens proc that takes and returns large extern struct by value" do run(<<-CRYSTAL).to_i.should eq(149) @[Extern] struct Foo @unused = uninitialized Int64 def initialize(@x : Int32, @y : Int32, @z : Int32) end end f = ->(foo : Foo) { Foo.new(foo.@x, foo.@y &* 2, foo.@z &* 3) } foo = f.call(Foo.new(100, 20, 3)) foo.@x &+ foo.@y &+ foo.@z CRYSTAL end # These specs *should* also work for 32 bits, but for now we'll # make sure they work in 64 bits (they probably work in 32 bits too, # it's just that the specs need to be a bit different) {% if flag?(:x86_64) || flag?(:aarch64) %} it "codegens proc that takes an extern struct with C ABI" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct Struct { int x; int y; }; void foo(struct Struct (*callback)(struct Struct)) { struct Struct s; s.x = 1; s.y = 2; callback(s); } C lib LibMylib struct Struct x : Int32 y : Int32 end alias Callback = Struct -> fun foo(callback : Callback) : LibMylib::Struct end class Global @@x = 0 @@y = 0 def self.x=(@@x) end def self.y=(@@y) end def self.x @@x end def self.y @@y end end LibMylib.foo(->(s) { Global.x = s.x Global.y = s.y }) Global.x &+ Global.y CRYSTAL end it "codegens proc that takes an extern struct with C ABI (2)" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(33)) struct Struct { int x; int y; }; void foo(struct Struct (*callback)(int, struct Struct, int)) { struct Struct s; s.x = 1; s.y = 2; callback(10, s, 20); } C lib LibMylib struct Struct x : Int32 y : Int32 end alias Callback = Int32, Struct, Int32 -> fun foo(callback : Callback) : LibMylib::Struct end class Global @@x = 0 @@y = 0 def self.x=(@@x) end def self.y=(@@y) end def self.x @@x end def self.y @@y end end LibMylib.foo(->(x, s, y) { Global.x = s.x &+ x Global.y = s.y &+ y }) Global.x &+ Global.y CRYSTAL end it "codegens proc that takes an extern struct with C ABI, callback returns nil" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct Struct { int x; int y; }; void foo(void (*callback)(struct Struct)) { struct Struct s; s.x = 1; s.y = 2; callback(s); } C lib LibMylib struct Struct x : Int32 y : Int32 end alias Callback = Struct -> fun foo(callback : Callback) : LibMylib::Struct end class Global @@x = 0 @@y = 0 def self.x=(@@x) end def self.y=(@@y) end def self.x @@x end def self.y @@y end end LibMylib.foo(->(s) { Global.x = s.x Global.y = s.y nil }) Global.x &+ Global.y CRYSTAL end it "codegens proc that takes and returns an extern struct with C ABI" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(303)) struct Struct { int x; int y; }; struct Struct foo(struct Struct (*callback)(struct Struct)) { struct Struct s; s.x = 1; s.y = 2; return callback(s); } C lib LibMylib struct Struct x : Int32 y : Int32 end alias Callback = Struct -> Struct fun foo(callback : Callback) : LibMylib::Struct end class Global @@x = 0 @@y = 0 def self.x=(@@x) end def self.y=(@@y) end def self.x @@x end def self.y @@y end end s2 = LibMylib.foo(->(s) { Global.x = s.x Global.y = s.y s.x = 100 s.y = 200 s }) Global.x &+ Global.y &+ s2.x &+ s2.y CRYSTAL end it "codegens proc that takes and returns an extern struct with C ABI" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(30)) struct Struct { int x; int y; }; struct Struct foo(struct Struct (*callback)(int, int)) { return callback(10, 20); } C lib LibMylib struct Struct x : Int32 y : Int32 end alias Callback = Int32, Int32 -> Struct fun foo(callback : Callback) : LibMylib::Struct end s2 = LibMylib.foo(->(x, y) { s = LibMylib::Struct.new s.x = x s.y = y s }) s2.x &+ s2.y CRYSTAL end it "codegens proc that takes and returns an extern struct with sret" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(12)) struct Struct { long long x; long long y; long long z; }; struct Struct foo(struct Struct (*callback)(struct Struct)) { struct Struct s; s.x = 1; s.y = 2; s.z = 3; return callback(s); } C lib LibMylib struct Struct x : Int64 y : Int64 z : Int64 end alias Callback = Struct -> Struct fun foo(callback : Callback) : LibMylib::Struct end class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end s2 = LibMylib.foo(->(s) { Global.x &+= s.x Global.x &+= s.y Global.x &+= s.z s }) Global.x &+= s2.x Global.x &+= s2.y Global.x &+= s2.z Global.x.to_i32 CRYSTAL end it "doesn't crash with proc with extern struct that's a closure" do codegen(<<-CRYSTAL) lib LibMylib struct Struct x : Int64 y : Int64 z : Int64 end end a = 1 f = ->(s : LibMylib::Struct) { a } s = LibMylib::Struct.new f.call(s) CRYSTAL end it "invokes proc with extern struct" do run(<<-CRYSTAL).to_i.should eq(30) lib LibMylib struct Struct x : Int32 y : Int32 end end class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end f = ->(s : LibMylib::Struct) { Global.x &+= s.x Global.x &+= s.y } s = LibMylib::Struct.new s.x = 10 s.y = 20 f.call(s) Global.x CRYSTAL end it "invokes proc with extern struct with sret" do run(<<-CRYSTAL).to_i.should eq(15) lib LibMylib struct Struct x : Int32 y : Int32 z : Int32 w : Int32 a : Int32 end end f = ->{ s = LibMylib::Struct.new s.x = 1 s.y = 2 s.z = 3 s.w = 4 s.a = 5 s } s = f.call s.x &+ s.y &+ s.z &+ s.w &+ s.a CRYSTAL end {% end %} end ================================================ FILE: spec/compiler/codegen/fun_spec.cr ================================================ require "../../spec_helper" describe "Codegen: fun" do it "sets external linkage by default" do mod = codegen(<<-CRYSTAL, inject_primitives: false, single_module: false) fun foo; end fun __crystal_foo; end CRYSTAL mod.functions["foo"].linkage.should eq(LLVM::Linkage::External) mod.functions["__crystal_foo"].linkage.should eq(LLVM::Linkage::External) end it "sets internal linkage to __crystal_ funs when compiling to single module" do mod = codegen(<<-CRYSTAL, inject_primitives: false, single_module: true) fun foo; end fun __crystal_foo; end CRYSTAL mod.functions["foo"].linkage.should eq(LLVM::Linkage::External) mod.functions["__crystal_foo"].linkage.should eq(LLVM::Linkage::Internal) end it "defines same fun 3 or more times (#15523)" do run(<<-CRYSTAL, Int32).should eq(3) fun foo : Int32 1 end fun foo : Int32 2 end fun foo : Int32 3 end foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/generic_class_spec.cr ================================================ require "../../spec_helper" describe "Code gen: generic class type" do it "codegens inherited generic class instance var" do run(<<-CRYSTAL).to_i.should eq(2) class Foo(T) def initialize(@x : T) end def x @x &+ 1 end end class Bar < Foo(Int32) end Bar.new(1).x CRYSTAL end it "instantiates generic class with default argument in initialize (#394)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo(T) def initialize(@x = 1) end def x @x end end Foo(Int32).new.x &+ 1 CRYSTAL end it "allows initializing instance variable (#665)" do run(<<-CRYSTAL).to_i.should eq(1) class SomeType(T) @x = 1 def x @x end end SomeType(Char).new.x CRYSTAL end it "allows initializing instance variable in inherited generic type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo(T) @x = 1 def x @x end end class Bar(T) < Foo(T) @y = 2 end Bar(Char).new.x CRYSTAL end it "declares instance var with virtual T (#1675)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo end class Generic(T) def initialize @value = uninitialized T end def value=(@value) end def value @value end end generic = Generic(Foo).new generic.value = Foo.new generic.value.foo CRYSTAL end it "runs generic instance var initializers in superclass's metaclass context (#4753)" do run(<<-CRYSTAL).to_i.should eq(1) class Bar(T) def x {% if T == Int32 %} 1 {% else %} 2 {% end %} end end class FooBase(T) @bar = Bar(T).new def bar @bar end end class Foo(T) < FooBase(T) end Foo(Int32).new.bar.x CRYSTAL end it "runs generic instance var initializers in superclass's metaclass context (2) (#6482)" do run(<<-CRYSTAL).to_i.should eq(1) class Bar(T) def x {% if T == FooBase(Int32) %} 1 {% else %} 2 {% end %} end end class FooBase(T) @bar = Bar(FooBase(T)).new def bar @bar end end class Foo(T) < FooBase(T) end Foo(Int32).new.bar.x CRYSTAL end it "doesn't run generic instance var initializers in formal superclass's context (#4753)" do run(<<-CRYSTAL).to_i.should eq(7) class Foo(T) @foo = T.new def foo @foo end end class Bar(T) < Foo(T) end class Baz def baz 7 end end Bar(Baz).new.foo.baz CRYSTAL end it "codegens static array size after instantiating" do run(<<-CRYSTAL).to_i.should eq(3) struct StaticArray(T, N) def size N end end alias Foo = Int32[3] x = uninitialized Int32[3] x.size CRYSTAL end it "inherited instance var initialize from generic to concrete (#2128)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo(T) @x = 42 def x @x end end class Bar < Foo(Int32) end Bar.new.x CRYSTAL end it "inherited instance var initialize from generic to generic to concrete (#2128)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo(T) @x = 10 def x @x end end class Bar(T) < Foo(T) @y = 32 def y @y end end class Baz < Bar(Int32) end baz = Baz.new baz.x &+ baz.y CRYSTAL end it "invokes super in generic class (#2354)" do run(<<-CRYSTAL).to_i.should eq(2) class Global @@x = 1 def self.x=(@@x) end def self.x @@x end end class Foo def foo Global.x = 2 end end class Bar(T) < Foo def foo super end end b = Bar(Int32).new b.foo Global.x CRYSTAL end it "uses big integer as generic type argument (#2353)" do run(<<-CRYSTAL).to_u64.should eq(2374623294237463578) require "prelude" MIN_RANGE = -2374623294237463578 MAX_RANGE = -MIN_RANGE class Hello(T) def self.t T end end Hello(MAX_RANGE).t CRYSTAL end it "doesn't use virtual + in type arguments (#2839)" do run(<<-CRYSTAL).to_string.should eq("Gen(Foo)") class Class def name : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end class Gen(T) end Gen(Foo).name CRYSTAL end it "doesn't use virtual + in type arguments for Tuple (#2839)" do run(<<-CRYSTAL).to_string.should eq("Tuple(Foo)") class Class def name : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end class Gen(T) end Tuple(Foo).name CRYSTAL end it "doesn't use virtual + in type arguments for NamedTuple (#2839)" do run(<<-CRYSTAL).to_string.should eq("NamedTuple(x: Foo)") class Class def name : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end class Gen(T) end NamedTuple(x: Foo).name CRYSTAL end it "codegens virtual generic metaclass macro method call" do run(<<-CRYSTAL).to_string.should eq("Bar(Int32)") class Class def name : String {{ @type.name.stringify }} end end class Foo(T) end class Bar(T) < Foo(T) end Bar(Int32).new.as(Foo(Int32)).class.name CRYSTAL end it "recomputes two calls that look the same due to generic type being instantiated (#7728)" do run(<<-CRYSTAL).to_string.should eq("hello") require "prelude" abstract class Base end class Gen(T) < Base def initialize(@x : T) end def x @x end end def foo(gen) gen.x gen.x end foo(Gen.new(1) || Gen.new(1.5)) foo(Gen.new(true) || Gen.new(1_u8)) foo(Gen.new("hello") || Gen.new('z')).as(String) CRYSTAL end it "doesn't consider abstract types for including types (#7200)" do codegen(<<-CRYSTAL) module Moo end abstract class Foo(T) include Moo def foo bar end end class Bar(T) < Foo(T) def bar end end Bar(Int32).new.as(Moo).foo CRYSTAL end it "doesn't consider abstract generic instantiation when restricting type (#5190)" do codegen(<<-CRYSTAL) abstract class Foo(E) abstract def foo end abstract class Bar(E) < Foo(E) end class Baz(E) < Bar(E) def foo end end ptr = Pointer(Foo(String)).malloc(1_u64) Baz(String).new x = ptr.value if x.is_a?(Bar) x.foo end CRYSTAL end it "doesn't crash on generic type restriction with initially no subtypes (#8411)" do codegen(<<-CRYSTAL) class Foo end class Baz(T) < Foo def baz end end def x(z) end f = uninitialized Foo if f.is_a?(Baz) x(f.baz) end Baz(Int32).new CRYSTAL end it "doesn't crash on generic type restriction with no subtypes (#7583)" do codegen(<<-CRYSTAL) require "prelude" class Foo end class Baz(T) < Foo def baz end end def x(z) end f = uninitialized Foo if f.is_a?(Baz) x(f.baz) end CRYSTAL end it "doesn't override guessed instance var in generic type if already declared in superclass (#9431)" do codegen(<<-CRYSTAL) class Foo @x = 0 end class Bar(T) < Foo @x = 0 end class Baz < Bar(Int32) @valid = true end Baz.new CRYSTAL end it "accesses generic type argument from superclass, def context (#10834)" do run(<<-CRYSTAL, Int32).should eq(7) class Foo(T) end class Bar(U) < Foo(U) def t T end end Bar(7).new.t CRYSTAL end it "accesses generic type argument from superclass, metaclass context" do run(<<-CRYSTAL, Int32).should eq(7) struct Int32 def self.new(x : Int32) x end end class Foo(T) end class Bar(U) < Foo(U) @x = T.new(7) end Bar(Int32).new.@x CRYSTAL end it "accesses generic type argument from superclass, macro context" do run(<<-CRYSTAL, Int32).should eq(1) class Foo(T) end class Bar(U) < Foo(U) def t {{ T == 7 ? 1 : 2 }} end end Bar(7).new.t CRYSTAL end it "codegens compile-time interpreted generic int128" do run(<<-CRYSTAL).to_i.should eq(4) require "prelude" CONST = 1_i128 + 2_i128 class Foo(T) def initialize() end def t_incr T + 1 end end class Bar < Foo(CONST) end Bar.new.t_incr CRYSTAL end end ================================================ FILE: spec/compiler/codegen/hash_literal_spec.cr ================================================ require "../../spec_helper" describe "Code gen: hash literal spec" do it "creates custom non-generic hash" do run(<<-CRYSTAL).to_i.should eq(90) class Custom def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end custom = Custom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "creates custom generic hash" do run(<<-CRYSTAL).to_i.should eq(90) class Custom(K, V) def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end custom = Custom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "creates custom generic hash with type vars" do run(<<-CRYSTAL).to_i.should eq(90) class Custom(K, V) def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end custom = Custom(Int32, Int32) {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "creates custom generic hash via alias (1)" do run(<<-CRYSTAL).to_i.should eq(90) class Custom(K, V) def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end alias MyCustom = Custom custom = MyCustom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "creates custom generic hash via alias (2)" do run(<<-CRYSTAL).to_i.should eq(90) class Custom(K, V) def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end alias MyCustom = Custom(Int32, Int32) custom = MyCustom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "doesn't crash on hash literal with proc pointer (#646)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" def blah 1 end b = {"a" => ->blah} b["a"].call CRYSTAL end it "creates custom non-generic hash in module" do run(<<-CRYSTAL).to_i.should eq(90) module Moo class Custom def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end end custom = Moo::Custom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "creates custom generic hash in module (#5684)" do run(<<-CRYSTAL).to_i.should eq(90) module Moo class Custom(K, V) def initialize @keys = 0 @values = 0 end def []=(key, value) @keys &+= key @values &+= value end def keys @keys end def values @values end end end custom = Moo::Custom {1 => 10, 2 => 20} custom.keys &* custom.values CRYSTAL end it "assignment in hash literal works" do run("require \"prelude\"; {k = 1 => v = 2}; k + v").to_i.should eq(3) end it "assignment in hash-like literal works" do run("require \"prelude\"; Hash(Int32, Int32){k = 1 => v = 2}; k + v").to_i.should eq(3) end end ================================================ FILE: spec/compiler/codegen/hooks_spec.cr ================================================ require "../../spec_helper" describe "Code gen: hooks" do it "does inherited macro" do run(<<-CRYSTAL).to_i.should eq(1) class Foo macro inherited @@x = 1 def self.x @@x end end end class Bar < Foo end Bar.x CRYSTAL end it "does included macro" do run(<<-CRYSTAL).to_i.should eq(1) module Foo macro included @@x = 1 def self.x @@x end end end class Bar include Foo end Bar.x CRYSTAL end it "does extended macro" do run(<<-CRYSTAL).to_i.should eq(1) module Foo macro extended @@x = 1 def self.x @@x end end end class Bar extend Foo end Bar.x CRYSTAL end it "does added method macro" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end class Foo macro method_added(d) Global.x = 1 end def foo; end end Global.x CRYSTAL end it "does inherited macro recursively" do run(<<-CRYSTAL).to_i.should eq(2) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end class Foo macro inherited Global.x &+= 1 end end class Bar < Foo end class Baz < Bar end Global.x CRYSTAL end it "does inherited macro before class body" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" class Global @@x = 123 def self.x=(@@x) end def self.x @@x end end class Foo macro inherited @@y : Int32 = Global.x def self.y @@y end end end class Bar < Foo Global.x &+= 1 end Bar.y CRYSTAL end it "does finished" do run(<<-CRYSTAL).to_i.should eq(4) class Foo A = [1] macro finished {% A[0] = A[0] + 1 %} end macro finished {% A[0] = A[0] * 2 %} end macro finished def self.foo {{ A[0] }} end end end Foo.foo CRYSTAL end it "fixes empty types in hooks (#3946)" do codegen(<<-CRYSTAL) lib LibC fun exit(x : Int32) : NoReturn end def bar(x) end module Moo def foo bar(moo) end end class Moo1 include Moo def moo 0 end end class Moo2 include Moo def moo LibC.exit(1) end end class Foo macro inherited io = uninitialized Moo io.foo end end class Bar < Foo end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/if_spec.cr ================================================ require "../../spec_helper" describe "Code gen: if" do it "codegens if without an else with true" do run("a = 1; if true; a = 2; end; a").to_i.should eq(2) end it "codegens if without an else with false" do run("a = 1; if false; a = 2; end; a").to_i.should eq(1) end it "codegens if with an else with false" do run("a = 1; if false; a = 2; else; a = 3; end; a").to_i.should eq(3) end it "codegens if with an else with true" do run("a = 1; if true; a = 2; else; a = 3; end; a").to_i.should eq(2) end it "codegens if inside def without an else with true" do run("def foo; a = 1; if true; a = 2; end; a; end; foo").to_i.should eq(2) end it "codegen if inside if" do run("a = 1; if false; a = 1; elsif false; a = 2; else; a = 3; end; a").to_i.should eq(3) end it "codegens if value from then" do run("if true; 1; else 2; end").to_i.should eq(1) end it "codegens if with union" do run("a = if true; 2.5_f32; else; 1; end; a.to_f").to_f64.should eq(2.5) end it "codes if with two whiles" do run("if true; while false; end; else; while false; end; end") end it "codegens if with int" do run("if 1; 2; else 3; end").to_i.should eq(2) end it "codegens if with nil" do run("require \"nil\"; if nil; 2; else 3; end").to_i.should eq(3) end it "codegens if of nilable type in then" do run("if false; nil; else; \"foo\"; end").to_string.should eq("foo") end it "codegens if of nilable type in then 2" do run("if 1 == 2; nil; else; \"foo\"; end").to_string.should eq("foo") end it "codegens if of nilable type in else" do run("if true; \"foo\"; else; nil; end").to_string.should eq("foo") end it "codegens if of nilable type in else 3" do run("if 1 == 1; \"foo\"; else; nil; end").to_string.should eq("foo") end it "codegens if with return and no else" do run("def foo; if true; return 1; end; 2; end; foo").to_i.should eq(1) end it "codegens if with return in both branches" do run("def foo; if true; return 1; else; return 2; end; end; foo").to_i.should eq(1) end it "codegen if with nested if that returns" do run(<<-CRYSTAL).to_i.should eq(1) def foo if true if true return 1 else return 2 end end 0 end foo CRYSTAL end it "codegen if with union type and then without type" do run(<<-CRYSTAL).to_i.should eq(1) def foo if true return 1 else 1 || 1.1 end return 0 end foo CRYSTAL end it "codegen if with union type and else without type" do run(<<-CRYSTAL).to_i.should eq(1) def foo if false 1 || 1.1 else return 1 end return 0 end foo CRYSTAL end it "codegens if with virtual" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar < Foo end f = Foo.new || Bar.new if f 1 else 2 end CRYSTAL end it "codegens nested if with var (ssa bug)" do run(<<-CRYSTAL).to_i.should eq(1) foo = 1 if 1 == 2 if 1 == 2 foo = 2 else foo = 3 end end foo CRYSTAL end it "codegens if with nested if that raises" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" struct Nil; def to_i; 0; end; end block = 1 || nil if 1 == 2 if block raise "Oh no" end else block end.to_i CRYSTAL end it "codegens if with return in else preserves type filter" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" def foo x = 1 || nil if x else return 0 end x + 1 end foo CRYSTAL end it "codegens bug #1729" do run(<<-CRYSTAL).to_i.should eq(3) n = true ? 3 : 3.2 z = if n.is_a?(Float64) || false 0 else n end z.to_i! CRYSTAL end {% if flag?(:bits64) %} it "codegens if with pointer 0x100000000 pointer" do run(<<-CRYSTAL).to_i.should eq(1) ptr = Pointer(Void).new(0x100000000_u64) if ptr 1 else 2 end CRYSTAL end {% end %} it "doesn't crash with if !var using var in else" do run(<<-CRYSTAL).to_i.should eq(1) foo = nil if !foo 1 else foo end 1 CRYSTAL end it "doesn't crash with if !is_a? using var in then" do run(<<-CRYSTAL).to_i.should eq(1) foo = 1 if !foo.is_a?(Int32) foo else 1 end 1 CRYSTAL end it "restricts with || always falsey" do run(<<-CRYSTAL).to_i.should eq(2) t = 1 if t.is_a?(String) || t.is_a?(String) t else 2 end CRYSTAL end it "considers or truthy/falsey right" do run(<<-CRYSTAL).to_i.should eq(2) t = 1 || 'a' if t.is_a?(Char) || t.is_a?(Char) 1 else 2 end CRYSTAL end it "codegens #3104" do codegen(<<-CRYSTAL) def foo yield end x = typeof(nil && 1) foo do if x end end x CRYSTAL end it "doesn't generate truthy if branch if doesn't need value (bug)" do codegen(<<-CRYSTAL) class Foo end x = nil if x nil else if 2 == 2 Foo.new else "" end end 1 CRYSTAL end it "doesn't crash no NoReturn var (true left cond) (#1823)" do codegen(<<-CRYSTAL) def foo arg = nil if true || arg.nil? return end arg end foo CRYSTAL end it "doesn't crash no NoReturn var (non-true left cond) (#1823)" do codegen(<<-CRYSTAL) def foo arg = nil if 1 == 2 || arg.nil? return end arg end foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/is_a_spec.cr ================================================ require "../../spec_helper" describe "Codegen: is_a?" do it "codegens is_a? true for simple type" do run("1.is_a?(Int)").to_b.should be_true end it "codegens is_a? false for simple type" do run("1.is_a?(Bool)").to_b.should be_false end it "codegens is_a? with union gives true" do run("(1 == 1 ? 1 : 'a').is_a?(Int)").to_b.should be_true end it "codegens is_a? with union gives false" do run("(1 == 1 ? 1 : 'a').is_a?(Char)").to_b.should be_false end it "codegens is_a? with union gives false" do run("(1 == 1 ? 1 : 'a').is_a?(Float)").to_b.should be_false end it "codegens is_a? with union gives true" do run("(1 == 1 ? 1 : 'a').is_a?(Object)").to_b.should be_true end it "codegens is_a? with nilable gives true" do run("(1 == 1 ? nil : Reference.new).is_a?(Nil)").to_b.should be_true end it "codegens is_a? with nilable gives false because other type 1" do run("(1 == 1 ? nil : Reference.new).is_a?(Reference)").to_b.should be_false end it "codegens is_a? with nilable gives false because other type 2" do run("(1 == 2 ? nil : Reference.new).is_a?(Reference)").to_b.should be_true end it "codegens is_a? with nilable gives false because no type" do run("(1 == 2 ? nil : Reference.new).is_a?(String)").to_b.should be_false end it "codegens is_a? with nilable gives false because no type" do run("1.is_a?(Object)").to_b.should be_true end it "doesn't error if result is discarded (#14113)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end (Foo.new || "").is_a?(Foo) 1 CRYSTAL end it "evaluate method on filtered type" do run("a = 1; a = 'a'; if a.is_a?(Char); a.ord; else; 0; end").to_i.chr.should eq('a') end it "evaluate method on filtered type nilable type not-nil" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end a = nil a = Foo.new if a.is_a?(Foo) a.foo else 2 end CRYSTAL end it "evaluate method on filtered type nilable type nil" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def foo 1 end end class Foo end a = Foo.new a = nil if a.is_a?(Nil) a.foo else 2 end CRYSTAL end it "evaluates method on filtered union type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize(x : Int32) @x = x end def x @x end end a = 1 a = Foo.new(2) if a.is_a?(Reference) a.x else 0 end CRYSTAL end it "evaluates method on filtered union type 2" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(x : Int32) @x = x end def x @x end end class Bar def initialize(x : Int32) @x = x end def x @x end end a = 1 a = Foo.new(2) a = Bar.new(3) if a.is_a?(Reference) a.x else 0 end CRYSTAL end it "evaluates method on filtered union type 3" do run(<<-CRYSTAL).to_i.should eq(5) require "prelude" a = 1 a = [1.1] a = [5] if a.is_a?(Enumerable) a[0] else 0 end.to_i CRYSTAL end it "codegens when is_a? is always false but properties are used" do run(<<-CRYSTAL).to_b.should be_false require "prelude" class Foo def obj; 1 end end foo = 1 foo.is_a?(Foo) && foo.obj && foo.obj CRYSTAL end it "codegens is_a? on right side of and" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def bar true end end foo = Foo.new || nil if 1 == 1 && foo.is_a?(Foo) && foo.bar 1 else 2 end CRYSTAL end it "codegens is_a? with virtual" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar < Foo end foo = Bar.new || Foo.new foo.is_a?(Bar) ? 1 : 2 CRYSTAL end it "codegens is_a? with virtual and nil" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar < Foo end f = Foo.new || Bar.new || nil f.is_a?(Foo) ? 1 : 2 CRYSTAL end it "codegens is_a? with virtual and module" do run(<<-CRYSTAL).to_b.should be_true module Bar end abstract class FooBase2 end abstract class FooBase < FooBase2 include Bar end class Foo < FooBase end class Foo2 < FooBase2 end f = Foo.new || Foo2.new f.is_a?(Bar) CRYSTAL end it "restricts simple type with union" do run(<<-CRYSTAL).to_i.should eq(2) a = 1 if a.is_a?(Int32 | Char) a &+ 1 else 0 end CRYSTAL end it "restricts union with union" do run(<<-CRYSTAL).to_i.should eq(3) struct Char def &+(other : Int32) other end end struct Bool def foo 2 end end a = 1 || 'a' || false if a.is_a?(Int32 | Char) a &+ 2 else a.foo end CRYSTAL end it "codegens is_a? with a Const does comparison and gives true" do run(<<-CRYSTAL).to_b.should be_true require "prelude" CONST = 1 1.is_a?(CONST) CRYSTAL end it "codegens is_a? with a Const does comparison and gives false" do run(<<-CRYSTAL).to_b.should be_false require "prelude" CONST = 1 2.is_a?(CONST) CRYSTAL end it "gives false if generic type doesn't match exactly" do run(<<-CRYSTAL).to_i.should eq(2) class Foo(T) end foo = Foo(Int32 | Float64).new foo.is_a?(Foo(Int32)) ? 1 : 2 CRYSTAL end it "does is_a? with more strict virtual type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo end class Bar < Foo def foo 2 end end f = Bar.new || Foo.new if f.is_a?(Bar) f.foo else 1 end CRYSTAL end it "codegens is_a? casts union to nilable" do run(<<-CRYSTAL).to_i.should eq(2) class Foo; end var = "hello" || Foo.new || nil if var.is_a?(Foo | Nil) var2 = var 1 else 2 end CRYSTAL end it "codegens is_a? casts union to nilable in method" do run(<<-CRYSTAL).to_i.should eq(2) class Foo; end def foo(var) if var.is_a?(Foo | Nil) var2 = var 1 else 2 end end var = "hello" || Foo.new || nil foo(var) CRYSTAL end it "codegens is_a? from virtual type to module" do run(<<-CRYSTAL).to_i.should eq(1) module Moo end class Foo end class Bar < Foo include Moo end class Baz < Foo include Moo end f = Bar.new || Baz.new if f.is_a?(Moo) g = f 1 else 2 end CRYSTAL end it "codegens is_a? from nilable reference union type to nil" do run(<<-CRYSTAL).to_i.should eq(2) class Foo end class Bar end a = Foo.new || Bar.new || nil if a.is_a?(Nil) b = a 1 else 2 end CRYSTAL end it "codegens is_a? from nilable reference union type to type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar end a = Foo.new || Bar.new || nil if a.is_a?(Foo) b = a 1 else 2 end CRYSTAL end it "says false for value.is_a?(Class)" do run(<<-CRYSTAL).to_b.should be_false 1.is_a?(Class) CRYSTAL end it "restricts type in else but lazily" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize(@x : Int32) end def x @x end end foo = Foo.new(1) x = foo.x if x.is_a?(Int32) z = x &+ 1 else z = x.foo_bar end z CRYSTAL end it "works with inherited generic class against an instantiation" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) end class Bar < Foo(Int32) end bar = Bar.new bar.is_a?(Foo(Int32)) CRYSTAL end it "doesn't work with inherited generic class against an instantiation (2)" do run(<<-CRYSTAL).to_b.should be_false class Class1 end class Class2 < Class1 end class Foo(T) end class Bar < Foo(Class2) end bar = Bar.new bar.is_a?(Foo(Class1)) CRYSTAL end it "works with inherited generic class against an instantiation (3)" do run(<<-CRYSTAL).to_b.should be_false class Foo(T) end class Bar < Foo(Int32) end bar = Bar.new bar.is_a?(Foo(Float32)) CRYSTAL end it "doesn't type merge (1) (#548)" do run(<<-CRYSTAL).to_b.should be_false class Base; end class Base1 < Base; end class Base2 < Base; end class Base3 < Base; end Base3.new.is_a?(Base1 | Base2) CRYSTAL end it "doesn't type merge (2) (#548)" do run(<<-CRYSTAL).to_b.should be_true class Base; end class Base1 < Base; end class Base2 < Base; end class Base3 < Base; end Base1.new.is_a?(Base1 | Base2) && Base2.new.is_a?(Base1 | Base2) CRYSTAL end it "doesn't skip assignment when used in combination with .is_a? (true case, then) (#1121)" do run(<<-CRYSTAL).to_i.should eq(124) a = 123 if (b = a).is_a?(Int32) b &+ 1 else a end CRYSTAL end it "doesn't skip assignment when used in combination with .is_a? (true case, else) (#1121)" do run(<<-CRYSTAL).to_i.should eq(125) a = 123 if (b = a).is_a?(Int32) a &+ 2 else b end CRYSTAL end it "doesn't skip assignment when used in combination with .is_a? (false case) (#1121)" do run(<<-CRYSTAL).to_i.should eq(124) a = 123 if (b = a).is_a?(Char) b else b &+ 1 end CRYSTAL end it "doesn't skip assignment when used in combination with .is_a? and && (#1121)" do run(<<-CRYSTAL).to_i.should eq(124) a = 123 if (1 == 1) && (b = a).is_a?(Char) b else a end b ? b &+ 1 : 0 CRYSTAL end it "transforms then if condition is always truthy" do run(<<-CRYSTAL).to_i.should eq(456) def foo 123 && 456 end if 1.is_a?(Int32) foo else 999 end CRYSTAL end it "transforms else if condition is always falsey" do run(<<-CRYSTAL).to_i.should eq(456) def foo 123 && 456 end if 1.is_a?(Char) 999 else foo end CRYSTAL end it "resets truthy state after visiting nodes (bug)" do run(<<-CRYSTAL).to_i.should eq(123) a = 123 if !1.is_a?(Int32) a = 456 end a CRYSTAL end it "does is_a? with generic class metaclass" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) end Foo(Int32).is_a?(Foo.class) CRYSTAL end it "says false for GenericChild(Base).is_a?(GenericBase(Child)) (#1294)" do run(<<-CRYSTAL).to_b.should be_false class Base end class Child < Base end class GenericBase(T) end class GenericChild(T) < GenericBase(T) end GenericChild(Base).new.is_a?(GenericBase(Child)) CRYSTAL end it "does is_a?/responds_to? twice (#1451)" do run(<<-CRYSTAL).to_i.should eq(4) a = 1 == 2 ? 1 : false if a.is_a?(Int32) && a.is_a?(Int32) 3 else 4 end CRYSTAL end it "does is_a? with && and true condition" do run(<<-CRYSTAL).to_i.should eq(3) a = 1 == 1 ? 1 : false if a.is_a?(Int32) && 1 == 1 3 else 4 end CRYSTAL end it "does is_a? for union of module and type" do run(<<-CRYSTAL).to_i.should eq(2) module Moo def moo 2 end end class Foo include Moo end class Bar include Moo end def foo(io) if io.is_a?(Moo) io.moo else 3 end end io = Foo.new.as(Moo) || 1 foo(io) CRYSTAL end it "does is_a? for virtual generic instance type against generic" do run(<<-CRYSTAL).to_i.should eq(2) class Foo(T) end class Bar(T) < Foo(T) end def foo(x : Bar) end Bar(Int32).new.as(Foo(Int32)).is_a?(Bar) ? 2 : 3 CRYSTAL end it "does is_a?(generic type) for nested generic inheritance (1) (#9660)" do run(<<-CRYSTAL, inject_primitives: false).to_b.should be_true class Cxx end class Foo(T) end class Bar(T) < Foo(T) end class Baz < Bar(Cxx) end Baz.new.is_a?(Foo) CRYSTAL end it "does is_a?(generic type) for nested generic inheritance (2)" do run(<<-CRYSTAL, inject_primitives: false).to_b.should be_true class Cxx end class Foo(T) end class Bar(T) < Foo(T) end class Baz(T) < Bar(T) end Baz(Cxx).new.is_a?(Foo) CRYSTAL end it "does is_a?(generic type) for nested generic inheritance, through upcast (1)" do run(<<-CRYSTAL, inject_primitives: false).to_b.should be_true class Cxx end class Foo(T) end class Bar(T) < Foo(T) end class Baz < Bar(Cxx) end Baz.new.as(Foo(Cxx)).is_a?(Bar) CRYSTAL end it "does is_a?(generic type) for nested generic inheritance, through upcast (2)" do run(<<-CRYSTAL, inject_primitives: false).to_b.should be_true class Cxx end class Foo(T) end class Bar(T) < Foo(T) end class Baz(T) < Bar(T) end Baz(Cxx).new.as(Foo(Cxx)).is_a?(Bar) CRYSTAL end it "doesn't consider generic type to be a generic type of a recursive alias (#3524)" do run(<<-CRYSTAL).to_b.should be_false class Gen(T) end alias Type = Int32 | Gen(Type) a = Gen(Int32).new a.is_a?(Type) CRYSTAL end it "codegens untyped var (#4009)" do codegen(<<-CRYSTAL) i = 1 1 || i.is_a?(Int32) ? "" : i CRYSTAL end it "visits 1.to_s twice, may trigger enclosing_call (#4364)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" B = String 1.to_s.is_a?(B) CRYSTAL end it "says true for Class.is_a?(Class.class) (#4374)" do run(<<-CRYSTAL).to_b.should be_true Class.is_a?(Class.class) CRYSTAL end it "says true for Class.is_a?(Class.class.class) (#4374)" do run(<<-CRYSTAL).to_b.should be_true Class.is_a?(Class.class.class) CRYSTAL end it "passes is_a? with generic module type on virtual type (#10302)" do run(<<-CRYSTAL).to_b.should be_true module Mod(T) end abstract struct Sup include Mod(Sup) end struct Sub < Sup end Sub.new.is_a?(Mod(Sup)) CRYSTAL end it "restricts metaclass against virtual metaclass type" do run(<<-CRYSTAL).to_i.should eq(1) class A end class B < A end x = B || A if x.is_a?(B.class) 1 elsif x.is_a?(A.class) 2 else 3 end CRYSTAL end it "restricts virtual metaclass against virtual metaclass type" do run(<<-CRYSTAL).to_i.should eq(1) class A end class B < A end class C < B end x = B || A if x.is_a?(B.class) 1 elsif x.is_a?(A.class) 2 else 3 end CRYSTAL end it "does is_a? with union type, don't resolve to virtual type (#10244)" do run(<<-CRYSTAL).to_b.should be_false class A end class B < A end class C < A end class D < A end x = D.new || C.new x.is_a?(B | C) CRYSTAL end it "does is_a? with union type as Union(X, Y), don't resolve to virtual type (#10244)" do run(<<-CRYSTAL).to_b.should be_false class A end class B < A end class C < A end class D < A end x = D.new || C.new x.is_a?(Union(B, C)) CRYSTAL end it "restricts union metaclass to metaclass (#12295)" do run(<<-CRYSTAL).to_i.should eq(2) x = true ? Union(String | Int32) : String if x.is_a?(String.class) 1 else 2 end CRYSTAL end it "does is_a? for generic type against generic class instance type (#12304)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" class A end class B(T) < A end a = B(Int32).new.as(A) b = a.as(B) b.is_a?(B(Int32)) CRYSTAL end it "virtual metaclass type is not virtual instance type (#12628)" do run(<<-CRYSTAL).to_b.should be_false abstract struct Base end struct Impl < Base end Base.as(Base | Base.class).is_a?(Base | Impl) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/lib_spec.cr ================================================ require "../../spec_helper" describe "Code gen: lib" do pending "codegens lib var set and get" do run(<<-CRYSTAL).to_i.should eq(1) lib LibC $errno : Int32 end LibC.errno = 1 LibC.errno CRYSTAL end it "call to void function" do run(<<-CRYSTAL) lib LibC fun srand(x : UInt32) : Void end def foo LibC.srand(0_u32) end foo CRYSTAL end it "allows passing type to LibC if it has a converter with to_unsafe" do codegen(<<-CRYSTAL) lib LibC fun foo(x : Int32) : Int32 end class Foo def to_unsafe 1 end end LibC.foo Foo.new CRYSTAL end it "allows passing type to LibC if it has a converter with to_unsafe (bug)" do codegen(<<-CRYSTAL) require "prelude" lib LibC fun foo(x : UInt8*) end def foo yield 1 end LibC.foo(foo &.to_s) CRYSTAL end it "allows setting/getting external variable as function pointer" do codegen(<<-CRYSTAL) require "prelude" lib LibC $x : -> end LibC.x = ->{} LibC.x.call CRYSTAL end it "can use enum as fun argument" do codegen(<<-CRYSTAL) enum Foo A end lib LibC fun foo(x : Foo) end LibC.foo(Foo::A) CRYSTAL end it "can use enum as fun return" do codegen(<<-CRYSTAL) enum Foo A end lib LibC fun foo : Foo end LibC.foo CRYSTAL end it "can use tuple as fun return" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(3)) struct s { int x; int y; }; struct s foo() { struct s a = {1, 2}; return a; } C lib LibFoo fun foo : {Int32, Int32} end tuple = LibFoo.foo tuple[0] + tuple[1] CRYSTAL end it "get fun field from struct (#672)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" lib Moo struct Type func : (Type*) -> Int32 end end p = Pointer(Moo::Type).malloc(1) p.value.func = -> (t: Moo::Type*) { 10 } p.value.func.call(p) CRYSTAL end it "get fun field from union (#672)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" lib Moo union Type func : (Type*) -> Int32 end end p = Pointer(Moo::Type).malloc(1) p.value.func = -> (t: Moo::Type*) { 10 } p.value.func.call(p) CRYSTAL end it "refers to lib type (#960)" do codegen(<<-CRYSTAL) lib Thing end Thing CRYSTAL end it "allows invoking out with underscore " do codegen(<<-CRYSTAL) lib Lib fun foo(x : Int32*) : Float64 end Lib.foo out _ CRYSTAL end it "passes int as another float type in literal" do codegen(<<-CRYSTAL) lib LibFoo fun foo(x : Int32) end LibFoo.foo 1234.5 CRYSTAL end it "passes nil to varargs (#1570)" do codegen(<<-CRYSTAL) lib LibFoo fun foo(...) end LibFoo.foo(nil) CRYSTAL end it "casts C fun to Crystal proc when accessing instance var (#2515)" do codegen(<<-CRYSTAL) require "prelude" lib LibFoo struct Some x : -> end end LibFoo::Some.new.to_s CRYSTAL end it "doesn't crash when casting -1 to UInt32 (#3594)" do codegen(<<-CRYSTAL) lib LibFoo fun foo(x : UInt32) : Nil end LibFoo.foo(-1) CRYSTAL end it "doesn't crash with nil and varargs (#4414)" do codegen(<<-CRYSTAL) lib LibFoo fun foo(Void*, ...) end x = nil LibFoo.foo(x) CRYSTAL end it "uses static array in lib extern (#5688)" do codegen(<<-CRYSTAL) lib LibFoo $x : Int32[10] end LibFoo.x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/macro_spec.cr ================================================ require "../../spec_helper" describe "Code gen: macro" do it "expands macro" do run("macro foo; 1 &+ 2; end; foo").to_i.should eq(3) end it "expands macro with arguments" do run(<<-CRYSTAL).to_i.should eq(3) macro foo(n) {{n}} &+ 2 end foo(1) CRYSTAL end it "expands macro that invokes another macro" do run(<<-CRYSTAL).to_i.should eq(3) macro foo def x 1 &+ 2 end end macro bar foo end bar x CRYSTAL end it "expands macro defined in class" do run(<<-CRYSTAL).to_i.should eq(1) class Foo macro foo def bar 1 end end foo end foo = Foo.new foo.bar CRYSTAL end it "expands macro defined in base class" do run(<<-CRYSTAL).to_i.should eq(1) class Object macro foo def bar 1 end end end class Foo foo end foo = Foo.new foo.bar CRYSTAL end it "expands inline macro" do run(<<-CRYSTAL).to_i.should eq(1) a = {{ 1 }} a CRYSTAL end it "expands inline macro for" do run(<<-CRYSTAL).to_i.should eq(6) a = 0 {% for i in [1, 2, 3] %} a &+= {{i}} {% end %} a CRYSTAL end it "expands inline macro if (true)" do run(<<-CRYSTAL).to_i.should eq(1) a = 0 {% if 1 == 1 %} a &+= 1 {% end %} a CRYSTAL end it "expands inline macro if (false)" do run(<<-CRYSTAL).to_i.should eq(0) a = 0 {% if 1 == 2 %} a &+= 1 {% end %} a CRYSTAL end it "finds macro in class" do run(<<-CRYSTAL).to_i.should eq(3) class Foo macro foo 1 &+ 2 end def bar foo end end Foo.new.bar CRYSTAL end it "expands def macro" do run(<<-CRYSTAL).to_i.should eq(1) def bar_baz 1 end def foo : Int32 {% begin %} bar_{{ "baz".id }} {% end %} end foo CRYSTAL end it "expands def macro with var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo : Int32 {{ @type }} a = {{ 1 }} end end Foo.new.foo CRYSTAL end it "expands def macro with @type.instance_vars" do run(<<-CRYSTAL).to_string.should eq("x") class Foo def initialize(@x : Int32) end def to_s : String {{ @type.instance_vars.first.stringify }} end end foo = Foo.new(1) foo.to_s CRYSTAL end it "expands def macro with @type.instance_vars with subclass" do run(<<-CRYSTAL).to_string.should eq("y") class Reference def to_s : String {{ @type.instance_vars.last.stringify }} end end class Foo def initialize(@x : Int32) end end class Bar < Foo def initialize(@x : Int32, @y : Int32) end end Bar.new(1, 2).to_s CRYSTAL end it "expands def macro with @type.instance_vars with virtual" do run(<<-CRYSTAL).to_string.should eq("y") class Reference def to_s : String {{ @type.instance_vars.last.stringify }} end end class Foo def initialize(@x : Int32) end end class Bar < Foo def initialize(@x : Int32, @y : Int32) end end (Bar.new(1, 2) || Foo.new(1)).to_s CRYSTAL end it "expands def macro with @type.name" do run(<<-CRYSTAL).to_string.should eq("Foo") class Foo def initialize(@x : Int32) end def to_s : String {{@type.name.stringify}} end end foo = Foo.new(1) foo.to_s CRYSTAL end it "expands macro and resolves type correctly" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo : Int32 {{ @type }} 1 end end class Bar < Foo Int32 = 2 end Bar.new.foo CRYSTAL end it "expands def macro with @type.name with virtual" do run(<<-CRYSTAL).to_string.should eq("Bar") class Reference def to_s : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end (Bar.new || Foo.new).to_s CRYSTAL end it "expands def macro with @type.name with virtual (2)" do run(<<-CRYSTAL).to_string.should eq("Foo") class Reference def to_s : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end (Foo.new || Bar.new).to_s CRYSTAL end it "allows overriding macro definition when redefining base class" do run(<<-CRYSTAL).to_string.should eq("OH NO") class Foo def inspect : String {{@type.name.stringify}} end end class Bar < Foo end class Foo def inspect "OH NO" end end Bar.new.inspect CRYSTAL end it "uses invocation context" do run(<<-CRYSTAL).to_string.should eq("Foo") macro foo def bar {{@type.name.stringify}} end end class Foo foo end Foo.new.bar CRYSTAL end it "allows macro with default arguments" do run(<<-CRYSTAL).to_i.should eq(3) def bar 2 end macro foo(x, y = :bar) {{x}} &+ {{y.id}} end foo(1) CRYSTAL end it "expands def macro with instance var and method call (bug)" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end class Foo @name : Int32? def foo : Int32 {{ @type }} name = 1 @name = name end end Foo.new.foo.to_i! CRYSTAL end it "expands @type.name in virtual metaclass (1)" do run(<<-CRYSTAL).to_string.should eq("Foo") class Class def to_s : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end p = Pointer(Foo.class).malloc(1_u64) p.value = Bar p.value = Foo p.value.to_s CRYSTAL end it "expands @type.name in virtual metaclass (2)" do run(<<-CRYSTAL).to_string.should eq("Bar") class Class def to_s : String {{ @type.name.stringify }} end end class Foo end class Bar < Foo end p = Pointer(Foo.class).malloc(1_u64) p.value = Foo p.value = Bar p.value.to_s CRYSTAL end it "doesn't skip abstract classes when defining macro methods" do run(<<-CRYSTAL).to_i.should eq(2) class Object def foo : Int32 {{ @type }} 1 end end class Type end class ModuleType < Type def foo 2 end end class Type1 < ModuleType end class Type2 < Type end t = Type1.new || Type2.new t.foo CRYSTAL end it "doesn't reuse macro nodes (bug)" do run(<<-CRYSTAL).to_i.should eq(2) struct Float def &+(other) self + other end end def foo(x) {% for y in [1, 2] %} x &+ 1 {% end %} end foo 1 foo(1.5).to_i! CRYSTAL end it "can use constants" do run(<<-CRYSTAL).to_i.should eq(1) CONST = 1 {{ CONST }} CRYSTAL end it "can refer to types" do run(<<-CRYSTAL).to_string.should eq("y") class Foo def initialize(@x : Int32, @y : Int32) end def foo : String {{ @type }} {{ Foo.instance_vars.last.name.stringify }} end end Foo.new(1, 2).foo CRYSTAL end it "runs macro with splat" do run(<<-CRYSTAL).to_i.should eq(3) macro foo(*args) {{args.size}} end foo 1, 1, 1 CRYSTAL end it "runs macro with arg and splat" do run(<<-CRYSTAL).to_i.should eq(3) macro foo(name, *args) {{args.size}} end foo bar, 1, 1, 1 CRYSTAL end it "expands macro that yields" do run(<<-CRYSTAL).to_i.should eq(3) def foo {% for i in 0 .. 2 %} yield {{i}} {% end %} end a = 0 foo do |x| a &+= x end a CRYSTAL end it "can refer to abstract (1)" do run(<<-CRYSTAL).to_b.should be_false class Foo end {{ Foo.abstract? }} CRYSTAL end it "can refer to abstract (2)" do run(<<-CRYSTAL).to_b.should be_true abstract class Foo end {{ Foo.abstract? }} CRYSTAL end it "can refer to @type" do run(<<-CRYSTAL).to_string.should eq("Foo") class Foo def foo : String {{@type.name.stringify}} end end Foo.new.foo CRYSTAL end it "can refer to union (1)" do run(<<-CRYSTAL).to_b.should be_false {{Int32.union?}} CRYSTAL end it "can refer to union (2)" do run(<<-CRYSTAL).to_b.should be_true class Foo def initialize @x = 1; @x = 1.1 end def foo {{ @type.instance_vars.first.type.union? }} end end Foo.new.foo CRYSTAL end it "can iterate union types" do run(<<-CRYSTAL).to_string.should eq("Float64-Int32") class Foo def initialize @x = 1; @x = 1.1 end def foo {{ @type.instance_vars.first.type.union_types.map(&.name).sort.join("-") }} end end Foo.new.foo CRYSTAL end it "can access type variables" do run(<<-CRYSTAL).to_string.should eq("Int32") class Foo(T) def foo {{ @type.type_vars.first.name.stringify }} end end Foo(Int32).new.foo CRYSTAL end it "can access type variables of a module" do run(<<-CRYSTAL).to_string.should eq("Int32") module Foo(T) def self.foo {{ @type.type_vars.first.name.stringify }} end end Foo(Int32).foo CRYSTAL end it "can access type variables that are not types" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) def foo {{ @type.type_vars.first.is_a?(NumberLiteral) }} end end Foo(1).new.foo CRYSTAL end it "can access type variables of a tuple" do run(<<-CRYSTAL).to_string.should eq("Int32") struct Tuple def foo {{ @type.type_vars.first.name.stringify }} end end {1, 2, 3}.foo CRYSTAL end it "can access type variables of a generic type" do run(<<-CRYSTAL).to_string.should eq("T-K") class Foo(T, K) def self.foo : String {{ @type.type_vars.map(&.stringify).join("-") }} end end Foo.foo CRYSTAL end it "receives &block" do run(<<-CRYSTAL).to_i.should eq(2) macro foo(&block) bar {{block}} end def bar yield 1 end foo do |x| x &+ 1 end CRYSTAL end it "executes with named arguments" do run(<<-CRYSTAL).to_i.should eq(3) macro foo(x = 1) {{x}} &+ 1 end foo x: 2 CRYSTAL end it "gets correct class name when there are classes in the middle" do run(<<-CRYSTAL).to_string.should eq("Qux") class Foo def class_desc : String {{@type.name.stringify}} end end class Bar < Foo end class Baz < Bar end class Qux < Bar end a = Pointer(Foo).malloc(1_u64) a.value = Qux.new a.value.class_desc CRYSTAL end it "transforms hooks (bug)" do codegen(<<-CRYSTAL) require "prelude" module GC def self.add_finalizer(object : T) object.responds_to?(:finalize) end end abstract class Foo ALL = Pointer(Foo).malloc(1_u64) macro inherited ALL.value = new end end class Bar < Foo end CRYSTAL end it "executes subclasses" do run(<<-CRYSTAL).to_string.should eq("Bar-Baz") class Foo end class Bar < Foo end class Baz < Foo end class Qux < Baz end {{ Foo.subclasses.map(&.name).join("-") }} CRYSTAL end it "executes all_subclasses" do run(<<-CRYSTAL).to_string.should eq("Bar-Baz") class Foo end class Bar < Foo end class Baz < Bar end {{ Foo.all_subclasses.map(&.name).join("-") }} CRYSTAL end it "gets enum members with @type.constants" do run(<<-CRYSTAL).to_i.should eq(0 + 1 + 2) enum Color Red Green Blue def self.red {{@type.constants[0]}} end def self.green {{@type.constants[1]}} end def self.blue {{@type.constants[2]}} end end Color.red.value &+ Color.green.value &+ Color.blue.value CRYSTAL end it "gets enum members as constants" do run(<<-CRYSTAL).to_string.should eq("Green") enum Color Red Green Blue end {{Color.constants[1].stringify}} CRYSTAL end it "says that enum has Flags annotation" do run(<<-CRYSTAL).to_b.should be_true @[Flags] enum Color Red Green Blue end {{Color.annotation(Flags) ? true : false}} CRYSTAL end it "says that enum doesn't have Flags annotation" do run(<<-CRYSTAL).to_b.should be_false enum Color Red Green Blue end {{Color.annotation(Flags) ? true : false}} CRYSTAL end it "gets methods" do run(<<-CRYSTAL).to_string.should eq("bar") class Foo def bar 1 end def first_method_name : String {{ @type.methods.map(&.name.stringify).first }} end end Foo.new.first_method_name CRYSTAL end it "copies base macro def to sub-subtype even after it was copied to a subtype (#448)" do run(<<-CRYSTAL).to_string.should eq("Baz") class Object def class_name : String {{@type.name.stringify}} end end class Foo @@children : Pointer(Foo) @@children = Pointer(Foo).malloc(1_u64) def self.children @@children end end Foo.children.value = Foo.new Foo.children.value.class_name class Bar < Foo; end Foo.children.value = Bar.new Foo.children.value.class_name class Baz < Bar; end Foo.children.value = Baz.new Foo.children.value.class_name CRYSTAL end it "recalculates method when virtual metaclass type is added" do run(<<-CRYSTAL).to_string.should eq("Test, RunnableTest") require "prelude" class Global @@x = [] of String @@runnables = [] of Runnable.class def self.x=(@@x) end def self.x @@x end def self.runnables @@runnables end end def run Global.runnables.each &.run end class Runnable end class Runnable macro inherited Global.runnables << self end def self.run : Nil Global.x << {{@type.name.stringify}} nil end end class Test < Runnable end run Global.x.clear class RunnableTest < Test end run Global.x.join(", ") CRYSTAL end it "correctly recomputes call (bug)" do run(<<-CRYSTAL).to_string.should eq("Baz") class Object def in_object in_class(1) end end class Class def in_class(x) bar end def bar : String {{@type.name.stringify}} end end class Foo end class Bar < Foo end f = Bar.new || Foo.new f.class.in_object class Baz < Foo end f2 = Baz.new || Foo.new f2.class.in_object CRYSTAL end it "doesn't override local variable when using macro variable" do run(<<-CRYSTAL).to_i.should eq(1) macro foo(x) %a = {{x}} %a end a = 1 foo(2) foo(3) a CRYSTAL end it "doesn't override local variable when using macro variable (2)" do run(<<-CRYSTAL).to_i.should eq(26) macro foo(x) %a = {{x}} &+ 10 %a end a = 1 z = foo(2) w = foo(3) a &+ z &+ w CRYSTAL end it "uses indexed macro variable" do run(<<-CRYSTAL).to_i.should eq(4 + 5 + 6 + 40 + 50 + 60) macro foo(*elems) {% for elem, i in elems %} %var{i} = {{elem}} {% end %} %total = 0 {% for elem, i in elems %} %total &+= %var{i} {% end %} %total end z = 0 z &+= foo 4, 5, 6 z &+= foo 40, 50, 60 z CRYSTAL end it "uses indexed macro variable with many keys" do run(<<-CRYSTAL).to_i.should eq(4 + 5 + 6) macro foo(*elems) {% for elem, i in elems %} %var{elem, i} = {{elem}} {% end %} %total = 0 {% for elem, i in elems %} %total &+= %var{elem, i} {% end %} %total end z = foo 4, 5, 6 z CRYSTAL end it "codegens macro def with splat (#496)" do run(<<-CRYSTAL).to_i.should eq(6) class Foo def bar(*args) : Int32 {{ @type }} args[0] &+ args[1] &+ args[2] end end Foo.new.bar(1, 2, 3) CRYSTAL end it "codegens macro def with default arg (similar to #496)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def bar(foo = 1) : Int32 {{ @type }} foo &+ 2 end end Foo.new.bar CRYSTAL end it "expands macro with default arg and splat (#784)" do run(<<-CRYSTAL).to_string.should eq("5") macro some_macro(a=5, *args) {{a.stringify}} end some_macro CRYSTAL end it "expands macro with default arg and splat (2) (#784)" do run(<<-CRYSTAL).to_string.should eq("1") macro some_macro(a=5, *args) {{a.stringify}} end some_macro 1, 2, 3, 4 CRYSTAL end it "expands macro with default arg and splat (3) (#784)" do run(<<-CRYSTAL).to_i.should eq(3) macro some_macro(a=5, *args) {{args.size}} end some_macro 1, 2, 3, 4 CRYSTAL end it "checks if macro expansion returns (#821)" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(123) macro pass return 123 end def me pass nil end me || 0 CRYSTAL end it "passes #826" do run(<<-CRYSTAL).to_i.should eq(123) macro foo macro bar {{yield}} end end foo do 123 end bar CRYSTAL end it "declares constant in macro (#838)" do run(<<-CRYSTAL).to_i.should eq(123) macro foo {{yield}} end foo do CONST = 123 end CONST CRYSTAL end it "errors if dynamic constant assignment after macro expansion" do assert_error <<-CRYSTAL, "dynamic constant assignment. Constants can only be declared at the top level or inside other types." macro foo X = 123 end def bar foo end bar CRYSTAL end it "finds macro from virtual type" do run(<<-CRYSTAL).to_i.should eq(123) class Foo macro foo 123 end def bar foo end end class Bar < Foo end a = Pointer(Foo).malloc(1_u64) a.value = Foo.new a.value.bar CRYSTAL end it "expands macro with escaped quotes (#895)" do run(<<-CRYSTAL).to_string.should eq(%(hello")) macro foo(x) "{{x}}\\"" end foo hello CRYSTAL end it "expands macro def with return (#1040)" do run(<<-CRYSTAL).to_i.should eq(123) class Foo def a : Int32 {{ @type }} return 123 end end Foo.new.a CRYSTAL end it "fixes empty types of macro expansions (#1379)" do run(<<-CRYSTAL).to_i.should eq(123) macro lala(exp) {{exp}} end def foo bar do return 123 end end def bar return yield end lala foo CRYSTAL end it "expands macro as class method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo macro bar 1 end end Foo.bar CRYSTAL end it "expands macro as class method and accesses @type" do run(<<-CRYSTAL).to_string.should eq("Foo") class Foo macro bar {{@type.stringify}} end end Foo.bar CRYSTAL end it "codegens macro with comment (bug) (#1396)" do run(<<-CRYSTAL).to_i.should eq(1) macro my_macro # {{ 1 }} {{ 1 }} end my_macro CRYSTAL end it "correctly resolves constant inside block in macro def" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield end class Foo Const = 123 def self.bar : Int32 {{ @type }} foo { Const } end end Foo.bar CRYSTAL end it "can access free variables" do run(<<-CRYSTAL).to_string.should eq("Int32") def foo(x : T) forall T {{ T.stringify }} end foo(1) CRYSTAL end it "types macro expansion bug (#1734)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo : Int32 {{ @type }} 1 || 2 end end class Bar < Foo end x = true ? Foo.new : Bar.new x.foo CRYSTAL end it "expands Path with resolve method" do run(<<-CRYSTAL).to_i.should eq(1) CONST = 1 macro id(path) {{path.resolve}} end id(CONST) CRYSTAL end it "can use macro inside array literal" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" macro foo 42 end ary = [foo] ary[0] CRYSTAL end it "can use macro inside hash literal" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" macro foo 42 end hash = {foo => foo} hash[foo] CRYSTAL end it "executes with named arguments for positional arg (1)" do run(<<-CRYSTAL).to_i.should eq(3) macro foo(x) {{x}} &+ 1 end foo x: 2 CRYSTAL end it "executes with named arguments for positional arg (2)" do run(<<-CRYSTAL).to_i.should eq(6) macro foo(x, y) {{x}} &+ {{y}} &+ 1 end foo x: 2, y: 3 CRYSTAL end it "executes with named arguments for positional arg (3)" do run(<<-CRYSTAL).to_i.should eq(6) class String def bytesize @bytesize end end macro foo(x, y) {{x}} &+ {{y}}.bytesize &+ 1 end foo y: "foo", x: 2 CRYSTAL end it "stringifies type without virtual marker" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo_m : Int32 {{ @type }}.foo end def self.foo 1 end end class Bar < Foo def self.foo 2 end end (Bar.new || Foo.new).foo_m CRYSTAL end it "uses tuple T in method with free vars" do run(<<-CRYSTAL).to_i.should eq(2) struct Tuple def foo(x : U) forall U {{T.size}} end end {1, 3}.foo(1) CRYSTAL end it "implicitly marks method as macro def when using @type" do run(<<-CRYSTAL).to_string.should eq("Bar") class Foo def method {{@type.stringify}} end end class Bar < Foo end Bar.new.as(Foo).method CRYSTAL end it "doesn't replace %s in string (#2178)" do run(<<-CRYSTAL).to_string.should eq("hello %s") {% begin %} "hello %s" {% end %} CRYSTAL end it "doesn't replace %q() (#2178)" do run(<<-CRYSTAL).to_string.should eq("hello") {% begin %} %q(hello) {% end %} CRYSTAL end it "replaces %s inside string inside interpolation (#2178)" do run(<<-CRYSTAL).to_string.should eq("hello world") require "prelude" {% begin %} %a = "world" "hello \#{ %a }" {% end %} CRYSTAL end it "replaces %s inside string inside interpolation, with braces (#2178)" do run(<<-CRYSTAL).to_string.should eq(%(hello [{"world", "world"}, "world"])) require "prelude" {% begin %} %a = "world" "hello \#{ [{ %a, %a }, %a] }" {% end %} CRYSTAL end it "retains original yield expression (#2923)" do run(<<-CRYSTAL).to_string.should eq("hi") macro foo def bar(baz) {{yield}} end end foo do baz end bar("hi") CRYSTAL end it "surrounds {{yield}} with begin/end" do run(<<-CRYSTAL).to_i.should eq(2) macro foo a = {{yield}} end a = 0 foo do 1 2 end a CRYSTAL end it "initializes instance var in macro" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(1) class Foo {% begin %} @x = 1 {% end %} end Foo.new.@x CRYSTAL end it "initializes class var in macro" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(1) class Foo {% begin %} @@x = 1 {% end %} def self.x @@x end end Foo.x CRYSTAL end it "expands @def in inline macro" do run(<<-CRYSTAL).to_string.should eq("foo") def foo {{@def.name.stringify}} end foo CRYSTAL end it "expands @def in macro" do run(<<-CRYSTAL).to_string.should eq("bar") macro foo {{@def.name.stringify}} end def bar foo end bar CRYSTAL end it "gets constant" do run(<<-CRYSTAL).to_i.should eq(42) class Foo Bar = 42 end {{ Foo.constant("Bar") }} CRYSTAL end it "determines if overrides (false)" do run(<<-CRYSTAL).to_b.should be_false class Foo def foo 1 end end class Bar < Foo end {{ Bar.overrides?(Foo, "foo") }} CRYSTAL end it "determines if overrides (true)" do run(<<-CRYSTAL).to_b.should be_true class Foo def foo 1 end end class Bar < Foo def foo 2 end end {{ Bar.overrides?(Foo, "foo") }} CRYSTAL end it "determines if overrides, through another class (true)" do run(<<-CRYSTAL).to_b.should be_true class Foo def foo 1 end end class Bar < Foo def foo 2 end end class Baz < Bar end {{ Baz.overrides?(Foo, "foo") }} CRYSTAL end it "determines if overrides, through module (true)" do run(<<-CRYSTAL).to_b.should be_true class Foo def foo 1 end end module Moo def foo 2 end end class Bar < Foo include Moo end class Baz < Bar end {{ Baz.overrides?(Foo, "foo") }} CRYSTAL end it "determines if overrides, with macro method (false)" do run(<<-CRYSTAL).to_b.should be_false class Foo def foo {{ @type }} end end class Bar < Foo end (Foo.new || Bar.new).foo def x {{ Bar.overrides?(Foo, "foo") }} end x CRYSTAL end it "determines if method exists (true)" do run(<<-CRYSTAL).to_b.should be_true class Foo def foo 42 end end {{ Foo.has_method?(:foo) }} CRYSTAL end it "determines if method exists (false)" do run(<<-CRYSTAL).to_b.should be_false class Foo def foo 42 end end {{ Foo.has_method?(:bar) }} CRYSTAL end it "forwards file location" do run(<<-CRYSTAL, filename: "bar.cr").to_string.should eq("bar.cr") macro foo bar end macro bar(file = __FILE__) {{file}} end foo CRYSTAL end it "forwards dir location" do run(<<-CRYSTAL, filename: "somedir/bar.cr").to_string.should eq("somedir") macro foo bar end macro bar(dir = __DIR__) {{dir}} end foo CRYSTAL end it "forwards line number" do run(<<-CRYSTAL, filename: "somedir/bar.cr", inject_primitives: false).to_i.should eq(9) macro foo bar end macro bar(line = __LINE__) {{line}} end foo CRYSTAL end it "keeps line number with no block" do run(<<-CRYSTAL, filename: "somedir/bar.cr", inject_primitives: false).to_i.should eq(6) macro foo {{ yield }} __LINE__ end foo CRYSTAL end it "keeps line number with a block" do run(<<-CRYSTAL, filename: "somedir/bar.cr", inject_primitives: false).to_i.should eq(6) macro foo {{ yield }} __LINE__ end foo do 1 end CRYSTAL end it "resolves alias in macro" do run(<<-CRYSTAL).to_i.should eq(2) alias Foo = Int32 | String {{ Foo.union_types.size }} CRYSTAL end it "gets default value of instance variable" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x = 1 def default {{@type.instance_vars.first.default_value}} end end Foo.new.default CRYSTAL end it "gets default value of instance variable of generic type" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" struct Int32 def self.foo 10 end end class Foo(T) @x : T = T.foo def default {{@type.instance_vars.first.default_value}} end end Foo(Int32).new.default CRYSTAL end it "gets default value of instance variable of inherited type that also includes module" do run(<<-CRYSTAL).to_i.should eq(10) module Moo @moo = 10 end class Foo include Moo def foo {{ @type.instance_vars.first.default_value }} end end class Bar < Foo end Bar.new.foo CRYSTAL end it "determines if variable has default value" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x = 1 @y : Int32 def initialize(@y) end def defaults { {{ @type.instance_vars.find { |i| i.name == "x" }.has_default_value? }}, {{ @type.instance_vars.find { |i| i.name == "y" }.has_default_value? }}, } end end x, y = Foo.new(2).defaults a = 0 a &+= 1 if x a &+= 2 if y a CRYSTAL end it "expands macro with op assign inside assign (#5568)" do run(<<-CRYSTAL).to_string.chomp.should eq("2") require "prelude" macro expand {{ yield }} end def foo {:foo => 1} end expand do x = foo[:foo] += 1 puts x end CRYSTAL end it "devirtualizes @type" do run(<<-CRYSTAL).to_string.should eq("Foo") class Foo def foo {{@type.id.stringify}} end end class Bar < Foo end (Foo.new || Bar.new).foo CRYSTAL end it "keeps heredoc contents inside macro" do run(<<-CRYSTAL).to_string.should eq(" %foo") macro foo <<-FOO %foo FOO end foo CRYSTAL end it "keeps heredoc contents with interpolation inside macro" do run(<<-CRYSTAL).to_string.should eq(" 42") require "prelude" macro foo %foo = 42 <<-FOO \#{ %foo } FOO end foo CRYSTAL end it "access to the program with @top_level" do run(<<-CRYSTAL).to_string.should eq("main") class Foo def bar {{@top_level.name.stringify}} end end Foo.new.bar CRYSTAL end it "responds correctly to has_constant? with @top_level" do run(<<-CRYSTAL).to_b.should be_true FOO = 1 class Foo def bar {{@top_level.has_constant?("FOO")}} end end Foo.new.bar CRYSTAL end it "does block unpacking inside macro expression (#13707)" do run(<<-CRYSTAL).to_i.should eq(10) {% begin %} {% data = [{1, 2}, {3, 4}] value = 0 data.each do |(k, v)| value += k value += v end %} {{ value }} {% end %} CRYSTAL end it "accepts compile-time flags" do run("{{ flag?(:foo) ? 1 : 0 }}", flags: %w(foo)).to_i.should eq(1) run("{{ flag?(:foo) ? 1 : 0 }}", Int32, flags: %w(foo)).should eq(1) end end ================================================ FILE: spec/compiler/codegen/magic_constants_spec.cr ================================================ require "../../spec_helper" describe "Code gen: magic constants" do it "does __LINE__" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(5) def foo(x = __LINE__) x end foo CRYSTAL end it "does __FILE__" do run(<<-CRYSTAL, filename: "/foo/bar/baz.cr").to_string.should eq("/foo/bar/baz.cr") def foo(x = __FILE__) x end foo CRYSTAL end it "does __DIR__" do run(<<-CRYSTAL, filename: "/foo/bar/baz.cr").to_string.should eq("/foo/bar") def foo(x = __DIR__) x end foo CRYSTAL end it "does __LINE__ with dispatch" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(10) def foo(z : Int32, x = __LINE__) x end def foo(z : String) 1 end a = 1 || "hello" foo(a) CRYSTAL end it "does __LINE__ when specifying one default arg with __FILE__" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(5) def foo(x, file = __FILE__, line = __LINE__) line end foo 1, "hello" CRYSTAL end it "does __LINE__ when specifying one normal default arg" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(27) require "primitives" def foo(x, z = 10, line = __LINE__) z &+ line end foo 1, 20 CRYSTAL end it "does __LINE__ when specifying one middle argument" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(27) require "primitives" def foo(x, line = __LINE__, z = 1) z &+ line end foo 1, z: 20 CRYSTAL end it "does __LINE__ in macro" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(5) macro foo(line = __LINE__) {{line}} end foo CRYSTAL end it "does __FILE__ in macro" do run(<<-CRYSTAL, filename: "/foo/bar/baz.cr").to_string.should eq("/foo/bar/baz.cr") macro foo(file = __FILE__) {{file}} end foo CRYSTAL end it "does __DIR__ in macro" do run(<<-CRYSTAL, filename: "/foo/bar/baz.cr").to_string.should eq("/foo/bar") macro foo(dir = __DIR__) {{dir}} end foo CRYSTAL end it "does __END_LINE__ without block" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(5) def foo(x = __END_LINE__) x end foo CRYSTAL end it "does __END_LINE__ with block" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(8) def foo(x = __END_LINE__) yield x end foo do 1 end CRYSTAL end it "does __END_LINE__ in macro without block" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(5) macro foo(line = __END_LINE__) {{line}} end foo CRYSTAL end it "does __END_LINE__ in macro with block" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(7) macro foo(line = __END_LINE__) {{line}} end foo do 1 end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/method_missing_spec.cr ================================================ require "../../spec_helper" describe "Code gen: method_missing" do it "does method_missing macro without args" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo_something 1 end macro method_missing(call) {{call.name.id}}_something end end Foo.new.foo CRYSTAL end it "does method_missing macro with args" do run(<<-CRYSTAL).to_i.should eq(6) class Foo macro method_missing(call) {{call.args.join(" &+ ").id}} end end Foo.new.foo(1, 2, 3) CRYSTAL end it "does method_missing macro with block" do run(<<-CRYSTAL).to_i.should eq(6) class Foo def foo_something yield 1 yield 2 yield 3 end macro method_missing(call) {{call.name.id}}_something {{call.block}} end end a = 0 Foo.new.foo do |x| a &+= x end a CRYSTAL end it "does method_missing macro with block but not using it" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def foo_something 1 &+ 2 end macro method_missing(call) {{call.name.id}}_something {{call.block}} end end Foo.new.foo CRYSTAL end it "does method_missing macro with virtual type (1)" do run(<<-CRYSTAL).to_string.should eq("Foococo") class Foo macro method_missing(call) "{{@type.name.id}}{{call.name.id}}" end end class Bar < Foo end foo = Foo.new || Bar.new foo.coco CRYSTAL end it "does method_missing macro with virtual type (2)" do run(<<-CRYSTAL).to_string.should eq("Barcoco") class Foo macro method_missing(call) "{{@type.name.id}}{{call.name.id}}" end end class Bar < Foo end foo = Bar.new || Foo.new foo.coco CRYSTAL end it "does method_missing macro with virtual type (3)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def lala 1 end macro method_missing(call) 2 end end class Bar < Foo end foo = Bar.new || Foo.new foo.lala CRYSTAL end it "does method_missing macro with virtual type (4)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo macro method_missing(call) 1 end end class Bar < Foo macro method_missing(call) 2 end end foo = Bar.new || Foo.new foo.lala CRYSTAL end it "does method_missing macro with virtual type (5)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo macro method_missing(call) 1 end end class Bar < Foo macro method_missing(call) 2 end end class Baz < Bar macro method_missing(call) 3 end end foo = Baz.new || Bar.new || Foo.new foo.lala CRYSTAL end it "does method_missing macro with virtual type (6)" do run(<<-CRYSTAL).to_i.should eq(2) abstract class Foo end class Bar < Foo macro method_missing(call) 2 end end class Baz < Bar def lala 3 end end foo = Bar.new || Baz.new foo.lala CRYSTAL end it "does method_missing macro with virtual type (7)" do run(<<-CRYSTAL).to_i.should eq(3) abstract class Foo end class Bar < Foo macro method_missing(call) 2 end end class Baz < Bar def lala 3 end end foo = Baz.new || Bar.new foo.lala CRYSTAL end it "does method_missing macro with virtual type (8)" do run(<<-CRYSTAL).to_string.should eq("Bar") class Foo macro method_missing(call) {{@type.name.stringify}} end end class Bar < Foo end foo = Foo.new foo.coco bar = Bar.new bar.coco CRYSTAL end it "does method_missing macro with module involved" do run(<<-CRYSTAL).to_i.should eq(1) module Moo def lala 1 end end class Foo include Moo macro method_missing(call) 2 end end Foo.new.lala CRYSTAL end it "does method_missing macro with top level method involved" do run(<<-CRYSTAL).to_i.should eq(1) def lala 1 end class Foo macro method_missing(call) 2 end def bar lala end end foo = Foo.new foo.bar CRYSTAL end it "does method_missing macro with included module" do run(<<-CRYSTAL).to_string.should eq("Foo") module Moo macro method_missing(call) {{@type.name.stringify}} end end class Foo include Moo end Foo.new.coco CRYSTAL end it "does method_missing with assignment (bug)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo macro method_missing(call) x = {{call.args[0]}} x end end foo = Foo.new foo.bar(1) CRYSTAL end it "does method_missing with assignment (2) (bug)" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end class Foo @x : Int32? macro method_missing(call) @x = {{call.args[0]}} @x end end foo = Foo.new foo.bar(1).to_i! CRYSTAL end it "does method_missing macro without args (with call)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo_something 1 end macro method_missing(call) {{call.name.id}}_something end end Foo.new.foo CRYSTAL end it "does method_missing macro with args (with call)" do run(<<-CRYSTAL).to_i.should eq(6) class Foo macro method_missing(call) {{call.args.join(" &+ ").id}} end end Foo.new.foo(1, 2, 3) CRYSTAL end it "forwards" do run(<<-CRYSTAL).to_i.should eq(6) class Wrapped def foo(x, y, z) x &+ y &+ z end end class Foo def initialize(@wrapped : Wrapped) end macro method_missing(call) @wrapped.{{call}} end end Foo.new(Wrapped.new).foo(1, 2, 3) CRYSTAL end it "does method_missing generating method" do run(<<-CRYSTAL).to_string.should eq("bar") class Foo macro method_missing(call) def {{call.name}} {{call.name.stringify}} end end end Foo.new.bar CRYSTAL end it "works with named arguments (#3654)" do run(<<-CRYSTAL).to_i.should eq(3) class A macro method_missing(call) {{call.named_args[0].value}} &+ {{call.named_args[1].value}} end end a = A.new a.b(x: 1, y: 2) CRYSTAL end it "works with named arguments that aren't legal variable names (#10381)" do run(<<-CRYSTAL).to_i.should eq(3) class A macro method_missing(call) {{call.named_args[0].value}} &+ {{call.named_args[1].value}} end end a = A.new a.b("@x": 1, Y: 2) CRYSTAL end it "finds method_missing with 'with ... yield'" do run(<<-CRYSTAL).to_i.should eq(10) class Foo def initialize(@x : Int32) end macro method_missing(call) @{{call.name.id}} end end def bar foo = Foo.new(10) with foo yield end bar do x end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/module_spec.cr ================================================ require "../../spec_helper" describe "Code gen: module" do it "codegens pointer of module with method" do run(<<-CRYSTAL).to_i.should eq(1) module Moo end class Foo include Moo def foo 1 end end p = Pointer(Moo).malloc(1_u64) p.value = Foo.new p.value.foo CRYSTAL end it "codegens pointer of module with method with two including types" do run(<<-CRYSTAL).to_i.should eq(2) module Moo end class Foo include Moo def foo 1 end end class Bar include Moo def foo 2 end end p = Pointer(Moo).malloc(1_u64) p.value = Foo.new p.value = Bar.new p.value.foo CRYSTAL end it "codegens pointer of module with method with two including types with one struct" do run(<<-CRYSTAL).to_i.should eq(2) module Foo end class Bar include Foo def foo 1 end end struct Coco include Foo def foo 2 end end p = Pointer(Foo).malloc(1_u64) p.value = Bar.new p.value = Coco.new p.value.foo CRYSTAL end it "codegens pointer of module with method with two including types with one struct (2)" do run(<<-CRYSTAL).to_i.should eq(2) module Foo end class Bar include Foo def foo 1 end end struct Coco include Foo def foo 2 end end p = Pointer(Foo).malloc(1_u64) p.value = Bar.new p.value = Coco.new x = p.value x.foo CRYSTAL end it "codegens pointer of module and pass value to method" do run(<<-CRYSTAL).to_i.should eq(1) module Foo end class Bar include Foo def foo 1 end end def foo(x) x.foo end p = Pointer(Foo).malloc(1_u64) p.value = Bar.new foo p.value CRYSTAL end it "codegens pointer of module with block" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Moo end class Foo include Moo def foo 1 end end struct Pointer def each yield value end end a = Pointer(Moo).malloc(1_u64) a.value = Foo.new x = nil a.each do |io| x = io end x.not_nil!.foo CRYSTAL end it "codegens module with virtual type" do run(<<-CRYSTAL).to_i.should eq(2) module Moo end class Foo include Moo def foo 1 end end class Bar < Foo def foo 2 end end p = Pointer(Moo).malloc(1_u64) p.value = Bar.new p.value.foo CRYSTAL end it "declares proc with module type" do run(<<-CRYSTAL).to_i.should eq(1) module Moo def moo 1 end end class Foo include Moo end class Bar include Moo end foo = ->(x : Moo) { x.moo } foo.call(Bar.new) CRYSTAL end it "declares proc with module type and invoke it with two different types that return themselves" do codegen(<<-CRYSTAL) module Moo def moo 1 end end class Foo include Moo end struct Bar include Moo end foo = ->(x : Moo) { x } foo.call(Foo.new) foo.call(Bar.new) CRYSTAL end it "codegens proc of a module that was never included" do codegen(<<-CRYSTAL) require "prelude" module Moo end ->(x : Moo) { x.foo } 1 CRYSTAL end it "codegens proc of module when generic type includes it" do run(<<-CRYSTAL).to_i.should eq(3) module Moo end class Foo(T) include Moo def foo 3 end end z = ->(x : Moo) { x.foo } z.call(Foo(Int32).new) CRYSTAL end it "invokes method on yielded module that has no instances (#1079)" do run(<<-CRYSTAL).to_i.should eq(456) require "prelude" module Mod end def foo ptr = Pointer(Mod).malloc(1_u64) yield ptr.value 123 rescue 456 end foo { |x| x.coco } CRYSTAL end it "expands modules to its including types (#1916)" do run(<<-CRYSTAL).to_i.should eq(1) class Reference def method(other : Reference) 1 end def method(other) 2 end end module Moo end class Foo include Moo end class Bar include Moo end x = Foo.new y = x.as(Moo) x.method(y) CRYSTAL end it "expands modules to its including types (2) (#1916)" do run(<<-CRYSTAL).to_i.should eq(1) class Reference def method(other : Reference) 1 end def method(other) 2 end end module Moo end module Moo::Sub include Moo end class File2 include Moo::Sub end file = File2.new file2 = file.as(Moo) file.method(file2) CRYSTAL end it "expands modules to its including types (3) (#1916)" do run(<<-CRYSTAL).to_i.should eq(2) class Object def method(other : Reference) 1 end def method(other) 2 end end module Moo end class Foo include Moo end struct Bar include Moo end x = Bar.new y = x.as(Moo) x.method(y) CRYSTAL end it "codegens cast to module with class and struct to nilable module" do run(<<-CRYSTAL).to_i.should eq(10) module Moo def bar 10 end end class Foo include Moo end struct Bar include Moo end def moo (Foo.new || Bar.new).as(Moo) end moo = moo() nilable = moo || nil if nilable nilable.bar else 20 end CRYSTAL end it "codegens cast to module that includes bool" do run(<<-CRYSTAL).to_i.should eq(2) module Moo end struct Bool include Moo end class Foo include Moo end Foo.new a = false.as(Moo) if a 1 else 2 end CRYSTAL end it "declares and includes generic module, in macros T is a tuple literal" do run(<<-CRYSTAL).to_string.should eq("TupleLiteral") module Moo(*T) def t {{T.class_name}} end end class Foo include Moo(Int32, Char) end Foo.new.t CRYSTAL end it "can instantiate generic module" do run(<<-CRYSTAL).to_i.should eq(10) struct Int32 def self.foo 10 end end module Foo(T) def self.foo T.foo end end Foo(Int32).foo CRYSTAL end it "can use generic module as instance variable type" do run(<<-CRYSTAL).to_i.should eq(3) module Moo(T) def foo 1 end end class Foo include Moo(Int32) end class Bar include Moo(Int32) def foo 2 end end class Mooer def initialize(@moo : Moo(Int32)) end def moo @moo.foo end end mooer = Mooer.new(Foo.new) x = mooer.moo mooer = Mooer.new(Bar.new) y = mooer.moo x &+ y CRYSTAL end it "can use generic module as instance variable type (2)" do run(<<-CRYSTAL).to_i.should eq(3) module Moo(T) def foo 1 end end class Foo(T) include Moo(T) end class Bar(T) include Moo(T) def foo 2 end end class Mooer def initialize(@moo : Moo(Int32)) end def moo @moo.foo end end mooer = Mooer.new(Foo(Int32).new) x = mooer.moo mooer = Mooer.new(Bar(Int32).new) y = mooer.moo x &+ y CRYSTAL end it "casts to union of module that is included in other module (#3323)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" module Moo def moo 0 end end module Moo2 include Moo end class Foo include Moo2 end class Bar < Foo def moo 10 end end struct Baz include Moo end bar = Bar.new.as(Int32 | Moo) bar.as(Moo).moo CRYSTAL end it "casts to union of generic module that is included in other module (#3323)" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" module Moo(T) def moo 0 end end module Moo2(T) include Moo(T) end class Foo include Moo2(Char) end class Bar < Foo def moo 10 end end struct Baz include Moo(Char) end bar = Bar.new.as(Int32 | Moo(Char)) bar.as(Moo(Char)).moo CRYSTAL end it "codegens dispatch of union with module (#3647)" do run(<<-CRYSTAL).to_i.should eq(234) module Moo end class Foo include Moo end class Bar < Foo end def foo(x : Int32) 1 end def foo(x) 234 end m = Bar.new.as(Moo) a = m || 1 foo(a) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/multi_assign_spec.cr ================================================ require "../../spec_helper" describe "Code gen: multi assign" do it "supports n to n assignment" do run(<<-CRYSTAL).to_i.should eq(123) a, b, c = 1, 2, 3 a &* 100 &+ b &* 10 &+ c CRYSTAL end context "without strict_multi_assign" do it "supports 1 to n assignment" do run(<<-CRYSTAL).to_i.should eq(123) class Foo def [](index) index &+ 1 end end a, b, c = Foo.new a &* 100 &+ b &* 10 &+ c CRYSTAL end it "doesn't raise if value size in 1 to n assignment doesn't match target count" do run(<<-CRYSTAL).to_i.should eq(4) require "prelude" begin a, b = [1, 2, 3] 4 rescue ex : Exception raise ex unless ex.message == "Multiple assignment count mismatch" 5 end CRYSTAL end end context "strict_multi_assign" do it "supports 1 to n assignment" do run(<<-CRYSTAL, flags: %w(strict_multi_assign)).to_i.should eq(123) require "prelude" class Foo include Indexable(Int32) def unsafe_fetch(index) index &+ 1 end def size 3 end end a, b, c = Foo.new a &* 100 &+ b &* 10 &+ c CRYSTAL end it "raises if value size in 1 to n assignment doesn't match target count" do run(<<-CRYSTAL, flags: %w(strict_multi_assign)).to_i.should eq(5) require "prelude" begin a, b = [1, 2, 3] 4 rescue ex : Exception raise ex unless ex.message == "Multiple assignment count mismatch" 5 end CRYSTAL end end it "supports m to n assignment, with splat on left-hand side (1)" do run(<<-CRYSTAL).to_i.should eq(12345) #{tuple_new} a, *b, c = 1, 2, 3, 4, 5 a &* 10000 &+ b[0] &* 1000 &+ b[1] &* 100 &+ b[2] &* 10 &+ c CRYSTAL end it "supports m to n assignment, with splat on left-hand side (2)" do run(<<-CRYSTAL).to_i.should eq(12345) #{tuple_new} *a, b, c = 1, 2, 3, 4, 5 a[0] &* 10000 &+ a[1] &* 1000 &+ a[2] &* 100 &+ b &* 10 &+ c CRYSTAL end it "supports m to n assignment, with splat on left-hand side (3)" do run(<<-CRYSTAL).to_i.should eq(12345) #{tuple_new} a, b, *c = 1, 2, 3, 4, 5 a &* 10000 &+ b &* 1000 &+ c[0] &* 100 &+ c[1] &* 10 &+ c[2] CRYSTAL end it "supports m to n assignment, splat is empty tuple (1)" do run(<<-CRYSTAL).to_b.should be_true #{tuple_new} _, *x, _ = 1, 2 x.is_a?(Tuple()) CRYSTAL end it "supports m to n assignment, splat is empty tuple (2)" do run(<<-CRYSTAL).to_b.should be_true #{tuple_new} *x, _, _ = 1, 2 x.is_a?(Tuple()) CRYSTAL end it "supports m to n assignment, splat is empty tuple (3)" do run(<<-CRYSTAL).to_b.should be_true #{tuple_new} _, _, *x = 1, 2 x.is_a?(Tuple()) CRYSTAL end it "supports 1 to n assignment, with splat on left-hand side (1)" do run(<<-CRYSTAL).to_i.should eq(12345) require "prelude" a, *b, c = {1, 2, 3, 4, 5} a &* 10000 &+ b[0] &* 1000 &+ b[1] &* 100 &+ b[2] &* 10 &+ c CRYSTAL end it "supports 1 to n assignment, with splat on left-hand side (2)" do run(<<-CRYSTAL).to_i.should eq(12345) #{range_new} #{include_indexable} *a, b, c = {1, 2, 3, 4, 5} a[0] &* 10000 &+ a[1] &* 1000 &+ a[2] &* 100 &+ b &* 10 &+ c CRYSTAL end it "supports 1 to n assignment, with splat on left-hand side (3)" do run(<<-CRYSTAL).to_i.should eq(12345) #{range_new} #{include_indexable} a, b, *c = {1, 2, 3, 4, 5} a &* 10000 &+ b &* 1000 &+ c[0] &* 100 &+ c[1] &* 10 &+ c[2] CRYSTAL end it "supports 1 to n assignment, splat is empty (1)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" _, *x, _ = {1, 2} x.is_a?(Tuple()) CRYSTAL end it "supports 1 to n assignment, splat is empty (2)" do run(<<-CRYSTAL).to_b.should be_true #{tuple_new} #{range_new} #{include_indexable} *x, _, _ = {1, 2} x.is_a?(Tuple()) CRYSTAL end it "supports 1 to n assignment, splat is empty (3)" do run(<<-CRYSTAL).to_b.should be_true #{tuple_new} #{range_new} #{include_indexable} _, _, *x = {1, 2} x.is_a?(Tuple()) CRYSTAL end it "supports 1 to n assignment, raises if too short" do run(<<-CRYSTAL).to_b.should be_true require "prelude" begin a, *b, c = [1] false rescue ex : IndexError ex.message == "Multiple assignment count mismatch" end CRYSTAL end it "supports 1 to n assignment, raises if out of bounds (1)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" begin *a, b, c = [1] false rescue ex : IndexError true end CRYSTAL end it "supports 1 to n assignment, raises if out of bounds (2)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" begin a, b, *c = [1] false rescue ex : IndexError true end CRYSTAL end end private def tuple_new <<-CRYSTAL struct Tuple def self.new(*args) args end end CRYSTAL end private def range_new <<-CRYSTAL struct Range(B, E) def initialize(@begin : B, @end : E, @exclusive : Bool = false) end end CRYSTAL end private def include_indexable <<-CRYSTAL struct Tuple(*T) include Indexable(Union(*T)) end CRYSTAL end ================================================ FILE: spec/compiler/codegen/named_args_spec.cr ================================================ require "../../spec_helper" describe "Code gen: named args" do it "calls with named arg" do run(<<-CRYSTAL).to_i.should eq(10) def foo(y = 2) y end foo y: 10 CRYSTAL end it "calls with named arg and other args" do run(<<-CRYSTAL).to_i.should eq(13) def foo(x, y = 2, z = 3) x &+ y &+ z end foo 1, z: 10 CRYSTAL end it "calls with named arg as object method" do run(<<-CRYSTAL).to_i.should eq(13) class Foo def foo(x, y = 2, z = 3) x &+ y &+ z end end Foo.new.foo 1, z: 10 CRYSTAL end it "calls twice with different types" do run(<<-CRYSTAL).to_i.should eq(5) struct Int32 def &+(other : Float) self + other end end def add(x, y = 1) x &+ y end value = 0 value &+= add(1, y: 2) value &+= add(1, y: 1.3) value.to_i! CRYSTAL end it "calls new with named arg" do run(<<-CRYSTAL).to_i.should eq(13) class Foo @value : Int32 def initialize(x, y = 2, z = 3) @value = x &+ y &+ z end def value @value end end Foo.new(1, z: 10).value CRYSTAL end it "uses named args in dispatch" do run(<<-CRYSTAL).to_i.should eq(22) class Foo def foo(x, z = 2) x &+ z &+ 1 end end class Bar def foo(x, z = 2) x &+ z end end a = Foo.new || Bar.new a.foo 1, z: 20 CRYSTAL end it "sends one regular argument as named argument" do run(<<-CRYSTAL).to_i.should eq(42) def foo(x) x end foo x: 42 CRYSTAL end it "sends two regular arguments as named arguments" do run(<<-CRYSTAL).to_i.should eq(42) def foo(x, y) x &+ y end foo x: 10, y: 32 CRYSTAL end it "sends two regular arguments as named arguments in inverted position (1)" do run(<<-CRYSTAL).to_string.should eq("foo") def foo(x, y) x end foo y: 42, x: "foo" CRYSTAL end it "sends two regular arguments as named arguments in inverted position (2)" do run(<<-CRYSTAL).to_i.should eq(42) def foo(x, y) y end foo y: 42, x: "foo" CRYSTAL end it "overloads based on required named args" do run(<<-CRYSTAL).to_i.should eq(10 + 20 + 30*40) def foo(x, *, y) x &+ y end def foo(x, *, z) x &* z end a = foo(10, y: 20) b = foo(30, z: 40) a &+ b CRYSTAL end it "overloads based on required named args, with restrictions" do run(<<-CRYSTAL).to_i.should eq(10 + 20 + 30*40) def foo(x, *, z : Int32) x &+ z end def foo(x, *, z : Float64) x &* z.to_i! end a = foo(10, z: 20) b = foo(30, z: 40.0) a &+ b CRYSTAL end it "uses bare splat in new (2)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(*, y = 22) @y = y end def y @y end end v1 = Foo.new.y v2 = Foo.new(y: 20).y v1 &+ v2 CRYSTAL end end ================================================ FILE: spec/compiler/codegen/named_tuple_spec.cr ================================================ require "../../spec_helper" describe "Code gen: named tuple" do it "codegens tuple index" do run(<<-CRYSTAL).to_i.should eq(42) t = {x: 42, y: 'a'} t[:x] CRYSTAL end it "codegens tuple index another order" do run(<<-CRYSTAL).to_i.should eq(42) t = {y: 'a', x: 42} t[:x] CRYSTAL end it "codegens tuple nilable index (1)" do run(<<-CRYSTAL).to_i.should eq(42) t = {x: 42, y: 'a'} t[:x]? || 84 CRYSTAL end it "codegens tuple nilable index (2)" do run(<<-CRYSTAL).to_i.should eq(42) t = {x: 'a', y: 42} t[:y]? || 84 CRYSTAL end it "codegens tuple nilable index (3)" do run(<<-CRYSTAL).to_i.should eq(84) t = {x: 'a', y: 42} t[:z]? || 84 CRYSTAL end it "passes named tuple to def" do run(<<-CRYSTAL).to_i.should eq(42) def foo(t) t[:x] end foo({y: 'a', x: 42}) CRYSTAL end it "gets size at compile time" do run(<<-CRYSTAL).to_i.should eq(2) struct NamedTuple def my_size {{ T.size }} end end {x: 10, y: 20}.my_size CRYSTAL end it "gets keys at compile time (1)" do run(<<-CRYSTAL).to_string.should eq("x") struct NamedTuple def keys {{ T.keys.map(&.stringify)[0] }} end end {x: 10, y: 2}.keys CRYSTAL end it "gets keys at compile time (2)" do run(<<-CRYSTAL).to_string.should eq("y") struct NamedTuple def keys {{ T.keys.map(&.stringify)[1] }} end end {x: 10, y: 2}.keys CRYSTAL end it "doesn't crash when overload doesn't match" do codegen(<<-CRYSTAL) struct NamedTuple def foo(other : self) end def foo(other) end end tup1 = {a: 1} tup2 = {b: 1} tup1.foo(tup2) CRYSTAL end it "assigns named tuple to compatible named tuple" do run(<<-CRYSTAL).to_i.should eq(42) ptr = Pointer({x: Int32, y: String}).malloc(1_u64) # Here the compiler should reorder the values to match # the type inside the pointer ptr.value = {y: "hello", x: 42} ptr.value[:x] CRYSTAL end it "upcasts named tuple inside compatible named tuple" do run(<<-CRYSTAL).to_string.should eq("Bar") def foo if 1 == 2 {name: "Foo", age: 20} else # Here the compiler should reorder the values to match # those of the tuple above {age: 40, name: "Bar"} end end foo[:name] CRYSTAL end it "assigns named tuple union to compatible named tuple" do run(<<-CRYSTAL).to_i.should eq(42) tup1 = {x: 1, y: "foo"} tup2 = {x: 3} tup3 = {y: "bar", x: 42} ptr = Pointer(typeof(tup1, tup2, tup3)).malloc(1_u64) # Here the compiler should reorder the values # inside tup3 to match the order of tup1 ptr.value = tup3 ptr.value[:x] CRYSTAL end it "upcasts named tuple union to compatible named tuple" do run(<<-CRYSTAL).to_i.should eq(42) def foo if 1 == 2 {x: 1, y: "foo"} || {x: 3} else {y: "bar", x: 42} end end foo[:x] CRYSTAL end it "assigns named tuple inside union to union with compatible named tuple" do run(<<-CRYSTAL).to_i.should eq(42) tup1 = {x: 21, y: "foo"} tup2 = {x: 3} union1 = tup1 || tup2 tup3 = {y: "bar", x: 42} tup4 = {x: 4} union2 = tup3 || tup4 ptr = Pointer(typeof(union1, union2)).malloc(1_u64) # Here the compiler should reorder the values inside # tup3 inside union2 to match the order of tup1 ptr.value = union2 ptr.value[:x] CRYSTAL end it "upcasts named tuple inside union to union with compatible named tuple" do run(<<-CRYSTAL).to_i.should eq(42) def foo if 1 == 2 tup1 = {x: 21, y: "foo"} tup2 = {x: 3} union1 = tup1 || tup2 union1 else tup3 = {y: "bar", x: 42} tup4 = {x: 4} union2 = tup3 || tup4 # Here the compiler should reorder the values inside # tup3 inside union2 to match the order of tup1 union2 end end foo[:x] CRYSTAL end it "allows named tuple covariance" do run(<<-CRYSTAL).to_i.should eq(42) class Obj def initialize @tuple = {foo: Foo.new} end def tuple=(@tuple) end def tuple @tuple end end class Foo def bar 21 end end class Bar < Foo def bar 42 end end obj = Obj.new obj.tuple = {foo: Bar.new} obj.tuple[:foo].bar CRYSTAL end it "merges two named tuple types with same keys but different types (1)" do run(<<-CRYSTAL).to_i.should eq(20) def foo if 1 == 2 {x: "foo", y: 10} else {y: nil, x: "foo"} end end val = foo[:y] val || 20 CRYSTAL end it "merges two named tuple types with same keys but different types (2)" do run(<<-CRYSTAL).to_i.should eq(10) def foo if 1 == 1 {x: "foo", y: 10} else {y: nil, x: "foo"} end end val = foo[:y] val || 20 CRYSTAL end it "codegens union of tuple of float with tuple of tuple of float" do run(<<-CRYSTAL).to_i.should eq(42) a = {x: 1.5} b = {x: {22.0, 20.0} } c = b || a v = c[:x] if v.is_a?(Float64) 10 else v[0].to_i! &+ v[1].to_i! end CRYSTAL end it "provides T as a named tuple literal" do run(<<-CRYSTAL).to_string.should eq("NamedTupleLiteral") struct NamedTuple def self.foo {{ T.class_name }} end end NamedTuple(x: Nil, y: Int32).foo CRYSTAL end it "assigns two same-size named tuple types to a same var (#3132)" do run(<<-CRYSTAL).to_i.should eq(2) t = {x: true} t t = {x: 2} t[:x] CRYSTAL end it "downcasts union inside tuple to value (#3907)" do codegen(<<-CRYSTAL) struct Foo end foo = Foo.new x = {a: 0, b: foo} z = x[:a] x = {a: 0, b: z} CRYSTAL end it "accesses T and creates instance from it" do run(<<-CRYSTAL).to_i.should eq(2) struct NamedTuple def named_args T end end class Foo def initialize(@x : Int32) end def x @x end end t = {a: Foo.new(1)} f = t.named_args[:a].new(2) f.x CRYSTAL end it "does to_s for NamedTuple class" do run(<<-CRYSTAL).to_string.should eq(%(NamedTuple(a: Int32, "b c": String, "+": Char))) require "prelude" NamedTuple(a: Int32, "b c": String, "+": Char).to_s CRYSTAL end it "doesn't error if NamedTuple includes a non-generic module (#10380)" do codegen(<<-CRYSTAL) module Foo end struct NamedTuple include Foo end x = uninitialized Foo x = {a: 1} CRYSTAL end end ================================================ FILE: spec/compiler/codegen/new_spec.cr ================================================ require "../../spec_helper" describe "Code gen: new" do it "codegens instance method with allocate" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco 1 end end Foo.allocate.coco CRYSTAL end it "codegens instance method with new and instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @coco = 2 end def coco @coco = 1 @coco end end f = Foo.new f.coco CRYSTAL end it "codegens instance method with new" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco 1 end end Foo.new.coco CRYSTAL end it "can create Reference" do run(<<-CRYSTAL).to_b.should be_false Reference.new.object_id == 0 CRYSTAL end it "inherits initialize" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(@x : Int32) end def x @x end end class Bar < Foo end Bar.new(42).x CRYSTAL end it "inherits initialize for generic type" do run(<<-CRYSTAL).to_i.should eq(42) class Foo(T) def initialize(@x : Int32) end end class Bar(T) < Foo(T) def x @x end end Bar(Int32).new(42).x CRYSTAL end it "overloads new and initialize, 1 (#2489)" do run(<<-CRYSTAL).to_i.should eq(10) class String def size 10 end end class Foo def initialize(@foo : Int32) end def self.new(bar) : self new bar.size end def self.new : self new "foo" end def foo @foo end end Foo.new.foo CRYSTAL end it "overloads new and initialize, 2 (#2489)" do run(<<-CRYSTAL).to_i.should eq(6) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end class Foo def initialize(@foo : Int32) end end class Bar < Foo def self.new(foo : Int32) : self Global.x = foo &+ 1 super end end Bar.new(5) Global.x CRYSTAL end it "overloads new and initialize, 3 (#2489)" do run(<<-CRYSTAL).to_i.should eq(6) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end class Foo def initialize(@foo : Int32) end def self.new(foo : Int32) : self Global.x = foo &+ 1 previous_def end end Foo.new(5) Global.x CRYSTAL end it "defines new for module" do run(<<-CRYSTAL).to_i.should eq(42) module Moo @x : Int32 def initialize(x : Int32) @x = x &+ 1 end def x @x end end class Foo include Moo end Foo.new(41).x CRYSTAL end it "finds super in deep hierarchy" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def initialize(@x : Int32) end end class Bar < Foo end class Baz < Bar end class Qux < Baz def initialize super(42) end def x @x end end Qux.new.x CRYSTAL end it "finds new in superclass if no initialize is defined (1)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def self.new 42 end end class Bar < Foo end Bar.new CRYSTAL end it "finds new in superclass if no initialize is defined (2)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo def self.new 42 end end class Bar < Foo def self.new(x) x end end Bar.new CRYSTAL end it "finds new in superclass for Enum" do run(<<-CRYSTAL).to_i.should eq(1) struct Enum def self.new(x : String) new(1) end end enum Color Red Green Blue end color = Color.new("foo") color.value CRYSTAL end it "can create Tuple with Tuple.new" do run(<<-CRYSTAL).to_i.should eq(0) require "prelude" Tuple.new.size CRYSTAL end it "evaluates initialize default value at the instance scope (1) (#731)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 def initialize(@x = bar) end def x @x end def bar 42 end end Foo.new.x CRYSTAL end it "evaluates initialize default value at the instance scope (2) (#731)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 def initialize(@x = bar, @y = 2) end def x @x end def y @y end def bar 20 end end foo = Foo.new(y: 22) foo.x &+ foo.y CRYSTAL end it "evaluates initialize default value at the instance scope (3) (#731)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 def initialize(@x = bar) yield 10, 12 end def x @x end def bar 20 end end total = 0 foo = Foo.new do |a, b| total &+= a total &+= b end total &+= foo.x total CRYSTAL end it "evaluates initialize default value at the instance scope (4) (#731)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 def initialize(@x = bar, &@block : -> Int32) end def x @x end def bar 22 end def block @block end end foo = Foo.new do 20 end foo.x &+ foo.block.call CRYSTAL end end ================================================ FILE: spec/compiler/codegen/next_spec.cr ================================================ require "../../spec_helper" describe "Code gen: next" do it "codegens next" do run(<<-CRYSTAL).to_i.should eq(1) def foo yield end foo do next 1 end CRYSTAL end it "codegens next conditionally" do run(<<-CRYSTAL).to_i.should eq(4) def foo yield 1 yield 2 yield 3 yield 4 end a = 0 foo do |i| next if i.unsafe_mod(2) == 0 a &+= i end a CRYSTAL end it "codegens next conditionally with int type (2)" do run(<<-CRYSTAL).to_i.should eq(100) def foo x = 0 x &+= yield 1 x &+= yield 2 x &+= yield 3 x &+= yield 4 x end foo do |i| if i == 1 next 10 elsif i == 2 next 20 elsif i == 3 next 30 end 40 end CRYSTAL end it "codegens next with break (1)" do run(<<-CRYSTAL).to_i.should eq(20) def foo yield 1 end foo do |i| if i == 1 break 20 else next 10 end end CRYSTAL end it "codegens next with break (2)" do run(<<-CRYSTAL).to_i.should eq(40) def foo a = 0 a &+= yield 1 a &+= yield 2 a end foo do |i| if i == 1 next 10 elsif i == 3 break 20 end 30 end CRYSTAL end it "codegens next with break (3)" do run(<<-CRYSTAL).to_i.should eq(20) def foo a = 0 a &+= yield 1 a &+= yield 2 a end foo do |i| if i == 1 next 10 elsif i == 2 break 20 end 30 end CRYSTAL end it "codegens next with while inside block" do run(<<-CRYSTAL).to_i.should eq(30) def foo a = 0 a &+= yield 4 a &+= yield 5 a end foo do |i| a = 0 b = 0 while a < 4 a &+= 1 next if a.unsafe_mod(2) == 0 b &+= a end if b == i next 10 end 20 end CRYSTAL end it "codegens next without expressions" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil; def to_i!; 0; end; end def foo yield end foo do if 1 == 1 1 else next end end.to_i! CRYSTAL end end ================================================ FILE: spec/compiler/codegen/nilable_cast_spec.cr ================================================ require "../../spec_helper" describe "Code gen: nilable cast" do it "does nilable cast (true)" do run(<<-CRYSTAL).to_i.should eq(42) x = 42 || "hello" y = x.as?(Int32) y || 84 CRYSTAL end it "does nilable cast (false)" do run(<<-CRYSTAL).to_i.should eq(84) x = "hello" || 42 y = x.as?(Int32) y || 84 CRYSTAL end it "does nilable cast (always true)" do run(<<-CRYSTAL).to_i.should eq(42) x = 42 y = x.as?(Int32) y || 84 CRYSTAL end it "does upcast" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def bar 1 end end class Bar < Foo def bar 2 end end foo = Bar.new.as?(Foo) if foo foo.bar else 3 end CRYSTAL end it "does cast to nil (1)" do run(<<-CRYSTAL).to_i.should eq(3) x = 1 y = x.as?(Nil) y ? 2 : 3 CRYSTAL end it "does cast to nil (2)" do run(<<-CRYSTAL).to_i.should eq(3) x = nil y = x.as?(Nil) y ? 2 : 3 CRYSTAL end it "types as? with wrong type (#2775)" do run(<<-CRYSTAL).to_i.should eq(20) x = 1.as?(String) x ? 10 : 20 CRYSTAL end it "codegens with NoReturn" do codegen(<<-CRYSTAL) lib LibC fun exit : NoReturn end def foo LibC.exit.as?(Int32) 10 end foo CRYSTAL end it "upcasts type to virtual (#3304)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 2 end end f = Foo.new.as?(Foo) f ? f.foo : 10 CRYSTAL end it "upcasts type to virtual (2) (#3304)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 2 end end class Gen(T) def self.cast(x) x.as?(T) end end f = Gen(Foo).cast(Foo.new) f ? f.foo : 10 CRYSTAL end it "casts with block var that changes type (#3341)" do codegen(<<-CRYSTAL) require "prelude" class Object def try yield self end end class Foo end x = Foo.new.as(Int32 | Foo) x.try &.as?(Foo) CRYSTAL end it "casts union type to nilable type (#9342)" do run(<<-CRYSTAL).to_i.should eq(10) struct Nil def foo 0 end end class Gen(T) def initialize(@value : Int32) end def foo @value end end a = Gen(String).new(10) || Gen(Int32).new(20) a.as?(Gen).foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/no_return_spec.cr ================================================ require "../../spec_helper" describe "Code gen: no return" do it "codegens if with NoReturn on then and union on else" do run("lib LibC; fun exit(c : Int32) : NoReturn; end; (if 1 == 2; LibC.exit(1); else; 1 || 2.5; end).to_i!").to_i.should eq(1) end it "codegens Pointer(NoReturn).malloc" do run("Pointer(NoReturn).malloc(1_u64); 1").to_i.should eq(1) end it "codegens if with no return and variable used afterwards" do codegen(<<-CRYSTAL) require "prelude" lib LibC fun exit2 : NoReturn end if (a = LibC.exit2) && a.size == 3 end CRYSTAL end it "codegen types exception handler as NoReturn if ensure is NoReturn" do codegen(<<-CRYSTAL) require "prelude" lib LibC fun foo : NoReturn end begin 1 ensure LibC.foo end CRYSTAL end it "codegens no return variable declaration (#1508)" do run(<<-CRYSTAL).to_i.should eq(1) foo = uninitialized NoReturn 1 CRYSTAL end it "codegens no return instance variable declaration (#1508)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @foo = uninitialized NoReturn @x = 1 end def x @x end end Foo.new.x CRYSTAL end it "codegens call with no return because of falsey if (#3661)" do codegen(<<-CRYSTAL) lib LibC fun exit(Int32) : NoReturn end def bar(x) x end def foo bar(yield 1) end foo do |x| LibC.exit(0) unless false end CRYSTAL end it "codegens untyped typeof (#5105)" do codegen(<<-CRYSTAL) require "prelude" typeof(raise("").foo) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/not_spec.cr ================================================ require "../../spec_helper" describe "Code gen: not" do it "codegens not number" do run("!1").to_b.should be_false end it "codegens not true" do run("!true").to_b.should be_false end it "codegens not false" do run("!false").to_b.should be_true end it "codegens not nil" do run("!nil").to_b.should be_true end it "codegens not nilable type (true)" do run(<<-CRYSTAL).to_b.should be_true class Foo end a = 1 == 2 ? Foo.new : nil !a CRYSTAL end it "codegens not nilable type (false)" do run(<<-CRYSTAL).to_b.should be_false class Foo end a = 1 == 1 ? Foo.new : nil !a CRYSTAL end it "codegens not pointer (true)" do run(<<-CRYSTAL).to_b.should be_true !Pointer(Int32).new(0_u64) CRYSTAL end it "codegens not pointer (false)" do run(<<-CRYSTAL).to_b.should be_false !Pointer(Int32).new(1_u64) CRYSTAL end it "doesn't crash" do run(<<-CRYSTAL).to_b.should be_false a = 1 !a.is_a?(String) && !a CRYSTAL end it "codegens not with inlinable value (#6451)" do codegen(<<-CRYSTAL) class Test def test false end end !Test.new.test nil CRYSTAL end end ================================================ FILE: spec/compiler/codegen/offsetof_spec.cr ================================================ require "../../spec_helper" describe "Code gen: offsetof" do it "returns offset allowing manual access of first struct field" do code = "struct Foo; @x = 42; def x; @x; end; end; f = Foo.new (pointerof(f).as(Void*) + offsetof(Foo, @x).to_i64()).as(Int32*).value == f.x" run(code).to_b.should be_true end it "returns offset allowing manual access of struct field that isn't first" do code = "struct Foo; @x = 1; @y = 42; def x; @x; end; def y; @y; end; end; f = Foo.new (pointerof(f).as(Void*) + offsetof(Foo, @y).to_i64()).as(Int32*).value == f.y" run(code).to_b.should be_true end it "returns offset allowing manual access of first class field" do code = "class Bar; @x = 42; def x; @x; end; end; b = Bar.new (b.as(Void*) + offsetof(Bar, @x).to_i64()).as(Int32*).value == b.x" run(code).to_b.should be_true end it "returns offset allowing manual access of class field that isn't first" do code = "class Bar; @x = 1; @y = 42; def x; @x; end; def y; @y; end; end; b = Bar.new (b.as(Void*) + offsetof(Bar, @y).to_i64()).as(Int32*).value == b.y" run(code).to_b.should be_true end it "returns offset allowing manual access of tuple items" do code = "foo = {1, 2_i8, 3} (pointerof(foo).as(Void*) + offsetof({Int32,Int8,Int32}, 2).to_i64).as(Int32*).value == 3" run(code).to_b.should be_true end it "returns offset of extern union" do run(<<-CRYSTAL).to_b.should be_true @[Extern(union: true)] struct Foo @x = 1.0_f32 @y = uninitialized UInt32 def y @y end end f = Foo.new (pointerof(f).as(Void*) + offsetof(Foo, @y).to_i64).as(UInt32*).value == f.y CRYSTAL end it "returns offset of `StaticArray#@buffer`" do run(<<-CRYSTAL).to_b.should be_true x = uninitialized Int32[4] pointerof(x.@buffer).value = 12345 (pointerof(x).as(Void*) + offsetof(Int32[4], @buffer).to_i64).as(Int32*).value == x.@buffer CRYSTAL end end ================================================ FILE: spec/compiler/codegen/op_assign_spec.cr ================================================ require "../../spec_helper" describe "Code gen: op assign" do it "evaluates exps once (#3398)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@value = 0 def self.value @@value end def self.value=(@@value) end end class Foo def bar=(bar) end def bar 0 end end def foo Global.value &+= 1 Foo.new end foo.bar &+= 2 Global.value CRYSTAL end it "evaluates exps once, [] (#3398)" do run(<<-CRYSTAL).to_i.should eq(11) class Global @@value = 0 def self.value @@value end def self.value=(@@value) end end class Foo def [](v) 0 end def []=(k, v) end end def foo Global.value &+= 1 Foo.new end def bar Global.value &+= 10 0 end foo[bar] &+= 2 Global.value CRYSTAL end end ================================================ FILE: spec/compiler/codegen/or_spec.cr ================================================ require "../../spec_helper" describe "Code gen: or" do it "codegens or with bool false and false" do run("false || false").to_b.should be_false end it "codegens or with bool false and true" do run("false || true").to_b.should be_true end it "codegens or with bool true and true" do run("true || true").to_b.should be_true end it "codegens or with bool true and false" do run("true || false").to_b.should be_true end it "codegens or with bool and int 1" do run("struct Bool; def to_i!; 0; end; end; (false || 2).to_i!").to_i.should eq(2) end it "codegens or with bool and int 2" do run("struct Bool; def to_i!; 0; end; end; (true || 2).to_i!").to_i.should eq(0) end it "codegens or with primitive type other than bool" do run("1 || 2").to_i.should eq(1) end it "codegens or with primitive type other than bool with union" do run("(1 || 1.5).to_f").to_f64.should eq(1) end it "codegens or with primitive type other than bool" do run("require \"nil\"; (nil || 2).to_i!").to_i.should eq(2) end it "codegens or with nilable as left node 1" do run(<<-CRYSTAL).to_i.should eq(2) require "nil" class Object; def to_i!; -1; end; end a = Reference.new a = nil (a || 2).to_i! CRYSTAL end it "codegens or with nilable as left node 2" do run(<<-CRYSTAL).to_i.should eq(-1) class Object; def to_i!; -1; end; end a = nil a = Reference.new (a || 2).to_i! CRYSTAL end it "codegens or with non-false union as left node" do run(<<-CRYSTAL).to_i.should eq(1) a = 1.5 a = 1 (a || 2).to_i! CRYSTAL end it "codegens or with nil union as left node 1" do run(<<-CRYSTAL).to_i.should eq(1) require "nil" a = nil a = 1 (a || 2).to_i! CRYSTAL end it "codegens or with nil union as left node 2" do run(<<-CRYSTAL).to_i.should eq(2) require "nil" a = 1 a = nil (a || 2).to_i! CRYSTAL end it "codegens or with bool union as left node 1" do run(<<-CRYSTAL).to_i.should eq(1) struct Bool; def to_i!; 0; end; end a = false a = 1 (a || 2).to_i! CRYSTAL end it "codegens or with bool union as left node 2" do run(<<-CRYSTAL).to_i.should eq(2) struct Bool; def to_i!; 0; end; end a = 1 a = false (a || 2).to_i! CRYSTAL end it "codegens or with bool union as left node 3" do run(<<-CRYSTAL).to_i.should eq(0) struct Bool; def to_i!; 0; end; end a = 1 a = true (a || 2).to_i! CRYSTAL end it "codegens or with bool union as left node 1" do run(<<-CRYSTAL).to_i.should eq(2) require "nil" struct Bool; def to_i!; 1; end; end a = false a = nil a = 2 (a || 3).to_i! CRYSTAL end it "codegens or with bool union as left node 2" do run(<<-CRYSTAL).to_i.should eq(3) require "nil" struct Bool; def to_i!; 1; end; end a = nil a = 2 a = false (a || 3).to_i! CRYSTAL end it "codegens or with bool union as left node 3" do run(<<-CRYSTAL).to_i.should eq(1) require "nil" struct Bool; def to_i!; 1; end; end a = nil a = 2 a = true (a || 3).to_i! CRYSTAL end it "codegens or with bool union as left node 4" do run(<<-CRYSTAL).to_i.should eq(3) require "nil" struct Bool; def to_i!; 1; end; end a = 2 a = true a = nil (a || 3).to_i! CRYSTAL end end ================================================ FILE: spec/compiler/codegen/pointer_spec.cr ================================================ require "../../spec_helper" describe "Code gen: pointer" do it "get pointer and value of it" do run("a = 1; b = pointerof(a); b.value").to_i.should eq(1) end it "get pointer of instance var" do run(<<-CRYSTAL).to_i.should eq(10) class Foo def initialize(value : Int32) @value = value end def value_ptr pointerof(@value) end end foo = Foo.new(10) value_ptr = foo.value_ptr value_ptr.value CRYSTAL end it "set pointer value" do run("a = 1; b = pointerof(a); b.value = 2; a").to_i.should eq(2) end it "get value of pointer to union" do run("a = 1.1; a = 1; b = pointerof(a); b.value.to_i!").to_i.should eq(1) end it "sets value of pointer to union" do run("p = Pointer(Int32|Float64).malloc(1_u64); a = 1; a = 2.5; p.value = a; p.value.to_i!").to_i.should eq(2) end it "increments pointer" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @a = 1 @b = 2 end def value p = pointerof(@a) p += 1_i64 p.value end end Foo.new.value CRYSTAL end it "codegens malloc" do run("p = Pointer(Int32).malloc(10_u64); p.value = 1; p.value &+ 1_i64").to_i.should eq(2) end it "codegens realloc" do run("p = Pointer(Int32).malloc(10_u64); p.value = 1; x = p.realloc(20_u64); x.value &+ 1_i64").to_i.should eq(2) end it "codegens pointer cast" do run("a = 1_i64; pointerof(a).as(Int32*).value").to_i.should eq(1) end it "codegens pointer cast to Nil (#8015)" do run("a = 1_i64; pointerof(a).as(Nil).nil? ? 3 : 7").to_i.should eq(3) end it "codegens pointer as if condition" do run("a = 0; pointerof(a) ? 1 : 2").to_i.should eq(1) end it "codegens null pointer as if condition" do run("Pointer(Int32).new(0_u64) ? 1 : 2").to_i.should eq(2) end it "gets pointer of instance variable in virtual type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @a = 1 end def foo pointerof(@a) end end class Bar < Foo end foo = Foo.new || Bar.new x = foo.foo x.value CRYSTAL end it "sets value of pointer to struct" do run(<<-CRYSTAL).to_i.should eq(20) lib LibC struct Color r, g, b, a : UInt8 end end color = Pointer(LibC::Color).malloc(1_u64) color.value.r = 10_u8 color2 = Pointer(LibC::Color).malloc(1_u64) color2.value.r = 20_u8 color.value = color2.value color.value.r CRYSTAL end it "changes through var and reads from pointer" do run(<<-CRYSTAL).to_i.should eq(2) x = 1 px = pointerof(x) x = 2 px.value CRYSTAL end it "creates pointer by address" do run(<<-CRYSTAL).to_i.should eq(123) x = Pointer(Int32).new(123_u64) x.address CRYSTAL end it "calculates pointer diff" do run(<<-CRYSTAL).to_i.should eq(1) x = 1 (pointerof(x) + 1_i64) - pointerof(x) CRYSTAL end it "can dereference pointer to func" do run(<<-CRYSTAL).to_i.should eq(1) def foo; 1; end x = ->foo y = pointerof(x) y.value.call CRYSTAL end it "gets pointer of argument that is never assigned to" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x) pointerof(x) end foo(1) 1 CRYSTAL end it "codegens nilable pointer type (1)" do run(<<-CRYSTAL).to_i.should eq(3) p = Pointer(Int32).malloc(1_u64) p.value = 3 a = 1 == 2 ? nil : p if a a.value else 4 end CRYSTAL end it "codegens nilable pointer type (2)" do run(<<-CRYSTAL).to_i.should eq(4) p = Pointer(Int32).malloc(1_u64) p.value = 3 a = 1 == 1 ? nil : p if a a.value else 4 end CRYSTAL end it "codegens nilable pointer type dispatch (1)" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x : Pointer) x.value end def foo(x : Nil) 0 end p = Pointer(Int32).malloc(1_u64) p.value = 3 a = 1 == 1 ? p : nil foo(a) CRYSTAL end it "codegens nilable pointer type dispatch (2)" do run(<<-CRYSTAL).to_i.should eq(0) def foo(x : Pointer) x.value end def foo(x : Nil) 0 end p = Pointer(Int32).malloc(1_u64) p.value = 3 a = 1 == 1 ? nil : p foo(a) CRYSTAL end it "assigns nil and pointer to nilable pointer type" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize end def x=(@x : Int32*?) end def x @x end end p = Pointer(Int32).malloc(1_u64) p.value = 3 foo = Foo.new foo.x = nil foo.x = p z = foo.x if z p.value else 2 end CRYSTAL end it "gets pointer to constant" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" FOO = 1 pointerof(FOO).value CRYSTAL end it "passes pointer of pointer to method" do run(<<-CRYSTAL).to_i.should eq(1) def foo(x) x.value.value end p = Pointer(Pointer(Int32)).malloc(1_u64) p.value = Pointer(Int32).malloc(1_u64) p.value.value = 1 foo p CRYSTAL end it "codegens pointer as if condition inside union (1)" do run(<<-CRYSTAL).to_i.should eq(2) ptr = Pointer(Int32).new(0_u64) || Pointer(Float64).new(0_u64) if ptr 1 else 2 end CRYSTAL end it "codegens pointer as if condition inside union (2)" do run(<<-CRYSTAL).to_i.should eq(30) if 1 == 1 ptr = Pointer(Int32).new(0_u64) else ptr = 10 end ptr ? 20 : 30 CRYSTAL end it "can use typedef pointer value get and set (#630)" do codegen(<<-CRYSTAL) lib LibFoo type MyObj = Int32* fun foo : MyObj end LibFoo.foo.value LibFoo.foo.value = 1 CRYSTAL end it "does pointerof class variable" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @@a = 1 def self.a_ptr pointerof(@@a) end def self.a @@a end end Foo.a_ptr.value = 2 Foo.a CRYSTAL end it "does pointerof class variable with class" do run(<<-CRYSTAL).to_i.should eq(2) class Bar def initialize(@x : Int32) end def x @x end end class Foo @@a = Bar.new(1) def self.a_ptr pointerof(@@a) end def self.a @@a end end Foo.a_ptr.value = Bar.new(2) Foo.a.x CRYSTAL end it "does pointerof read variable" do run(<<-CRYSTAL).to_i.should eq(123) class Foo def initialize @x = 1 end def x @x end end foo = Foo.new pointerof(foo.@x).value = 123 foo.x CRYSTAL end it "can assign nil to void pointer" do codegen(<<-CRYSTAL) ptr = Pointer(Void).malloc(1_u64) ptr.value = ptr.value CRYSTAL end it "can pass any pointer to something expecting void* in lib call" do codegen(<<-CRYSTAL) lib LibFoo fun foo(x : Void*) : Float64 end LibFoo.foo(Pointer(Int32).malloc(1_u64)) CRYSTAL end it "can pass any pointer to something expecting void* in lib call, with to_unsafe" do codegen(<<-CRYSTAL) lib LibFoo fun foo(x : Void*) : Float64 end class Foo def to_unsafe Pointer(Int32).malloc(1_u64) end end LibFoo.foo(Foo.new) CRYSTAL end it "uses correct llvm module for typedef metaclass (#2877)" do run(<<-CRYSTAL) lib LibFoo type Foo = Void* type Bar = Void* end class Class def foo foo(1) end def foo(x) end end struct Pointer def foo T.foo end end foo = uninitialized LibFoo::Foo* bar = uninitialized LibFoo::Bar* foo.foo bar.foo 1 CRYSTAL end it "passes arguments correctly for typedef metaclass (#8544)" do run <<-CRYSTAL lib LibFoo type Foo = Void* end class Class def foo(x) x end end x = 1 LibFoo::Foo.foo(x) Pointer(Void).foo(x) CRYSTAL end it "generates correct code for Pointer.malloc(0) (#2905)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize(@value : Int32) end def value @value end end foo = Foo.new(3) Pointer(Int32 | UInt8[9]).malloc(0_u64) foo.value CRYSTAL end it "compares pointers through typedef" do run(<<-CRYSTAL).to_b.should be_true module Comparable(T) def ==(other : T) (self <=> other) == 0 end end struct Pointer(T) include Comparable(Pointer) def <=>(other : Pointer) 0 end end lib LibFoo type Ptr = Void* end ptr = Pointer(Void).malloc(1_u64).as(LibFoo::Ptr) ptr == ptr CRYSTAL end # FIXME: `$external_var` implies __declspec(dllimport), but we only have an # object file, so MinGW-w64 fails linking (actually MSVC also emits an # LNK4217 linker warning) {% unless flag?(:win32) && flag?(:gnu) %} it "takes pointerof lib external var" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(111)) int external_var = 0; C lib LibFoo $external_var : Int32 end LibFoo.external_var = 1 ptr = pointerof(LibFoo.external_var) x = ptr.value ptr.value = 10 y = ptr.value ptr.value = 100 z = LibFoo.external_var x + y + z CRYSTAL end {% end %} end ================================================ FILE: spec/compiler/codegen/previous_def_spec.cr ================================================ require "../../spec_helper" describe "codegen: previous_def" do it "codegens previous def" do run(<<-CRYSTAL).to_i.should eq(2) def foo 1 end def foo previous_def &+ 1 end foo CRYSTAL end it "codegens previous def when inside fun and forwards args" do run(<<-CRYSTAL).to_i.should eq(6) def foo(z) z &+ 1 end def foo(z) ->(x : Int32) { x &+ previous_def } end x = foo(2) x.call(3) CRYSTAL end it "codegens previous def when inside fun with self" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @x = 1 end def bar @x end end class Foo def bar x = ->{ previous_def } end end Foo.new.bar.call CRYSTAL end it "correctly passes named arguments" do run(<<-CRYSTAL).to_i.should eq(4) def foo(x, *args, other = 1) other end def foo(x, *args, other = 1) previous_def end foo(1, 2, 3, other: 4) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/primitives_spec.cr ================================================ require "../../spec_helper" describe "Code gen: primitives" do it "codegens bool" do run("true").to_b.should be_true run("false").to_b.should be_false end it "codegens int" do run("1").to_i.should eq(1) end it "codegens long" do run("1_i64").to_i.should eq(1) end it "codegens int128" do # LLVM's JIT doesn't seem to support 128 # bit integers well regarding GenericValue run(<<-CRYSTAL).to_i.should eq(1) require "prelude" 1_i128.to_i CRYSTAL end it "codegens uint128" do # LLVM's JIT doesn't seem to support 128 # bit integers well regarding GenericValue run(<<-CRYSTAL).to_i.should eq(1) require "prelude" 1_u128.to_i CRYSTAL end it "codegens char" do run("'a'").to_i.should eq('a'.ord) end it "codegens char ord" do run("'a'.ord").to_i.should eq('a'.ord) end it "codegens f32" do run("2.5_f32").to_f32.should eq(2.5_f32) end it "codegens f64" do run("2.5_f64").to_f64.should eq(2.5_f64) end it "codegens string" do run(%("foo")).to_string.should eq("foo") end describe "arithmetic primitives" do # more detailed tests are done through the `primitives_spec` suite on a new # generation of the compiler it "codegens 1 + 2" do run(%(require "prelude"; 1 + 2)).to_i.should eq(3) end it "codegens 1 &+ 2" do run(%(1 &+ 2)).to_i.should eq(3) end it "codegens 1 - 2" do run(%(require "prelude"; 1 - 2)).to_i.should eq(-1) end it "codegens 1 &- 2" do run(%(1 &- 2)).to_i.should eq(-1) end it "codegens 2 * 3" do run(%(require "prelude"; 2 * 3)).to_i.should eq(6) end it "codegens 2 &* 3" do run(%(2 &* 3)).to_i.should eq(6) end it "codegens 8.unsafe_div 3" do run(%(8.unsafe_div 3)).to_i.should eq(2) end it "codegens 8.unsafe_mod 3" do run(%(10.unsafe_mod 3)).to_i.should eq(1) end it "codegens 16.unsafe_shr 2" do run(%(16.unsafe_shr 2)).to_i.should eq(4) end it "codegens 16.unsafe_shl 2" do run(%(16.unsafe_shl 2)).to_i.should eq(64) end it "codegens 1.to_i16!" do run("1.to_i16!").to_i.should eq(1) end it "codegens 1.to_i16" do run(%(require "prelude"; 1.to_i16)).to_i.should eq(1) end it "codegens 1.to_f!" do run("1.to_f!").to_f64.should eq(1.0) end it "codegens 1.to_f" do run(%(require "prelude"; 1.to_f)).to_f64.should eq(1.0) end it "skips bounds checking when to_i produces same type" do run("1.to_i32").to_i.should eq(1) end end it "defined method that calls primitive (bug)" do run(<<-CRYSTAL).to_i.should eq(1) struct Int64 def foo to_u64! end end a = 1_i64 a.foo.to_i! CRYSTAL end it "codegens __LINE__" do run(<<-CRYSTAL, inject_primitives: false).to_i.should eq(2) __LINE__ CRYSTAL end it "codegens crystal_type_id with union type" do run(<<-CRYSTAL).to_b.should be_true class Foo end class Bar < Foo end f = Foo.allocate || Bar.allocate f.crystal_type_id == Foo.allocate.crystal_type_id CRYSTAL end it "doesn't treat `(1 == 1) == true` as `1 == 1 == true` (#328)" do run("(1 == 1) == true").to_b.should be_true end it "passes issue #328" do run("((1 == 1) != (2 == 2))").to_b.should be_false end pending "codegens pointer of int" do run(<<-CRYSTAL).to_i.should eq(5) ptr = Pointer(Int).malloc(1_u64) ptr.value = 1 ptr.value = 2_u8 ptr.value = 3_u16 ptr.value = 4_u32 (ptr.value + 1).to_i32 CRYSTAL end pending "sums two numbers out of an [] of Number" do run(<<-CRYSTAL).to_f32.should eq(2.5) p = Pointer(Number).malloc(2_u64) p.value = 1 (p + 1_i64).value = 1.5 (p.value + (p + 1_i64).value).to_f32 CRYSTAL end it "codegens crystal_type_id for class" do codegen(%(String.crystal_type_id)) end it "can invoke cast on primitive typedef (#614)" do codegen(<<-CRYSTAL) lib Test type K = Int32 fun foo : K end Test.foo.to_i! CRYSTAL end it "can invoke binary on primitive typedef (#614)" do codegen(<<-CRYSTAL) lib Test type K = Int32 fun foo : K end Test.foo &+ 1 CRYSTAL end it "can invoke binary on primitive typedef (2) (#16097)" do codegen(<<-CRYSTAL) lib Test type K = Int32 fun foo : K end Test.foo == Test.foo CRYSTAL end it "can invoke pointer primitives on typedef" do codegen(<<-CRYSTAL) lib Test type K = Void* fun foo : K end Test.foo + 1 Test.foo - Test.foo Test.foo.realloc(1) CRYSTAL end it "can invoke struct setter on primitive typedef" do codegen(<<-CRYSTAL) lib Test struct Foo x : Int32 end type K = Foo fun foo : K end Test.foo.x = 1 CRYSTAL end pending "can invoke proc call on primitive typedef" do codegen(<<-CRYSTAL) lib Test type K = -> fun foo : K end Test.foo.call CRYSTAL end it "allows redefining a primitive method" do run(<<-CRYSTAL).to_i.should eq(42) struct Int32 def *(other : Int32) 42 end end 1 * 2 CRYSTAL end it "doesn't optimize away call whose obj is not passed as self (#2226)" do run(<<-CRYSTAL).to_i.should eq(2) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo Global.x = 2 3 end foo.class.crystal_type_id Global.x CRYSTAL end it "uses built-in llvm function that returns a tuple" do run(<<-CRYSTAL).to_i.should eq(3) lib Intrinsics fun sadd_i32_with_overflow = "llvm.sadd.with.overflow.i32"(a : Int32, b : Int32) : {Int32, Bool} end x, o = Intrinsics.sadd_i32_with_overflow(1, 2) x CRYSTAL end it "gets crystal class instance type id" do run(<<-CRYSTAL).to_b.should be_true class Foo end Foo.new.crystal_type_id == Foo.crystal_instance_type_id CRYSTAL end describe "va_arg" do # On Windows and AArch64 llvm's va_arg instruction works incorrectly. {% unless flag?(:win32) || flag?(:aarch64) %} it "uses llvm's va_arg instruction" do mod = codegen(<<-CRYSTAL) struct VaList @[Primitive(:va_arg)] def next(type) end end list = VaList.new list.next(Int32) CRYSTAL type = {% if LibLLVM::IS_LT_150 %} "%VaList*" {% else %} "ptr" {% end %} str = mod.to_s str.should contain("va_arg #{type} %list") end it "works with C code" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(6)) extern int foo_f(int,...); int foo() { return foo_f(3,1,2,3); } C lib LibFoo fun foo() : LibC::Int end fun foo_f(count : Int32, ...) : LibC::Int sum = 0 VaList.open do |list| count.times do |i| sum += list.next(Int32) end end sum end LibFoo.foo CRYSTAL end {% end %} end describe "atomicrmw" do it "codegens atomicrmw with enums" do run(<<-CRYSTAL).to_i.should eq(3) enum RMWBinOp Add = 1 end enum Ordering SequentiallyConsistent = 7 end @[Primitive(:atomicrmw)] def atomicrmw(op : RMWBinOp, ptr : Int32*, val : Int32, ordering : Ordering, singlethread : Bool) : Int32 end x = 1 atomicrmw(:add, pointerof(x), 2, :sequentially_consistent, false) x CRYSTAL end it "codegens atomicrmw with enums" do run(<<-CRYSTAL).to_i.should eq(3) enum RMWBinOp Add = 1 end enum Ordering SequentiallyConsistent = 7 end @[Primitive(:atomicrmw)] def atomicrmw(op : RMWBinOp, ptr : Int32*, val : Int32, ordering : Ordering, singlethread : Bool) : Int32 end x = 1 atomicrmw(RMWBinOp::Add, pointerof(x), 2, Ordering::SequentiallyConsistent, false) x CRYSTAL end # TODO: remove once support for 1.4 is dropped it "codegens atomicrmw with symbols" do run(<<-CRYSTAL).to_i.should eq(3) @[Primitive(:atomicrmw)] def atomicrmw(op : Symbol, ptr : Int32*, val : Int32, ordering : Symbol, singlethread : Bool) : Int32 end x = 1 atomicrmw(:add, pointerof(x), 2, :sequentially_consistent, false) x CRYSTAL end end it "allows @[Primitive] on method that has body" do run(<<-CRYSTAL).to_string.should eq("hello") module Moo @[Primitive(:symbol_to_s)] def self.symbol_to_s(symbol : Symbol) : String untyped end end Moo.symbol_to_s(:hello) CRYSTAL end it "allows @[Primitive] on fun declarations" do run(<<-CRYSTAL).to_i.should eq(1) lib LibFoo @[Primitive(:enum_value)] fun enum_value(x : Int32) : Int32 end LibFoo.enum_value(1) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/private_spec.cr ================================================ require "../../spec_helper" describe "Codegen: private" do it "codegens private def in same file" do compile(<<-CRYSTAL) private def foo 1 end foo CRYSTAL end it "codegens overloaded private def in same file" do compile(<<-CRYSTAL) private def foo(x : Int32) 1 end private def foo(x : Char) 2 end a = 3 || 'a' foo a CRYSTAL end it "codegens class var of private type with same name as public type (#11620)" do compile(<<-CRYSTAL, <<-CRYSTAL) module Foo @@x = true end CRYSTAL private module Foo @@x = 1 end CRYSTAL end it "codegens class vars of private types with same name (#11620)" do compile(<<-CRYSTAL, <<-CRYSTAL) private module Foo @@x = true end CRYSTAL private module Foo @@x = 1 end CRYSTAL end it "doesn't include filename for private types" do run(<<-CRYSTAL, filename: "foo").to_string.should eq("Foo") private class Foo def foo {{@type.stringify}} end end Foo.new.foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/proc_spec.cr ================================================ require "../../spec_helper" describe "Code gen: proc" do it "call simple proc literal" do run("x = -> { 1 }; x.call").to_i.should eq(1) end it "call proc literal with arguments" do run("f = ->(x : Int32) { x &+ 1 }; f.call(41)").to_i.should eq(42) end it "call proc literal with return type" do run(<<-CRYSTAL).to_b.should be_true f = -> : Int32 | Float64 { 1 } x = f.call x.is_a?(Int32) && x == 1 CRYSTAL end it "call proc pointer" do run("def foo; 1; end; x = ->foo; x.call").to_i.should eq(1) end it "call proc pointer with args" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x, y) x &+ y end f = ->foo(Int32, Int32) f.call(1, 2) CRYSTAL end it "call proc pointer of instance method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @x = 1 end def coco @x end end foo = Foo.new f = ->foo.coco f.call CRYSTAL end it "call proc pointer of instance method that raises" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def coco raise "foo" end end foo = Foo.new f = ->foo.coco f.call rescue 1 CRYSTAL end it "codegens proc with another var" do run(<<-CRYSTAL) def foo(x) bar(x, -> {}) end def bar(x, proc) end foo(1) CRYSTAL end it "codegens proc that returns a virtual type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco; 1; end end class Bar < Foo def coco; 2; end end x = -> { Foo.new || Bar.new } x.call.coco CRYSTAL end it "codegens proc that accepts a union and is called with a single type" do run(<<-CRYSTAL).to_i.should eq(2) struct Float def &+(other) self + other end end f = ->(x : Int32 | Float64) { x &+ 1 } f.call(1).to_i! CRYSTAL end it "makes sure that proc pointer is transformed after type inference" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Bar def initialize(@x : Int32) end def x @x end end class Foo def on_something Bar.new(1) end end def _on_(p : Foo*) p.value.on_something.x end c = ->_on_(Foo*) a = Foo.new c.call(pointerof(a)) CRYSTAL end it "binds function pointer to associated call" do run(<<-CRYSTAL).to_i.should eq(12) class Foo def initialize(@e : Int32) end def on_something @e end end def _on_(p : Foo*) p.value.on_something end c = ->_on_(Foo*) a = Foo.new(12) a.on_something c.call(pointerof(a)) CRYSTAL end it "call simple proc literal with return" do run("x = -> { return 1 }; x.call").to_i.should eq(1) end it "calls proc pointer with union (passed by value) arg" do run(<<-CRYSTAL).to_i.should eq(1) struct Number def abs; self; end end f = ->(x : Int32 | Float64) { x.abs } f.call(1 || 1.5).to_i! CRYSTAL end it "allows passing proc type to C automatically" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" lib LibC fun qsort(base : Void*, nel : LibC::SizeT, width : LibC::SizeT, callback : (Void*, Void* -> Int32)) end ary = [3, 1, 4, 2] LibC.qsort(ary.to_unsafe.as(Void*), LibC::SizeT.new(ary.size), LibC::SizeT.new(sizeof(Int32)), ->(a : Void*, b : Void*) { a = a.as(Int32*) b = b.as(Int32*) a.value <=> b.value }) ary[0] CRYSTAL end it "allows proc pointer where self is a class" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.bla 1 end end f = ->Foo.bla f.call CRYSTAL end it "codegens proc literal hard type inference (1)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def initialize(@x : NoReturn) end def x @x end end def foo(s) Foo.new(s.x) end def bar ->(s : Foo) { ->foo(Foo) } end bar 1 CRYSTAL end it "automatically casts proc that returns something to proc that returns void" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo(x : ->) x.call end foo ->{ Global.x = 1 } Global.x CRYSTAL end it "allows proc type of enum type" do run(<<-CRYSTAL).to_i.should eq(1) lib LibFoo enum MyEnum X = 1 end end ->(x : LibFoo::MyEnum) { x }.call(LibFoo::MyEnum::X) CRYSTAL end it "allows proc type of enum type with base type" do run(<<-CRYSTAL).to_i.should eq(1) lib LibFoo enum MyEnum : UInt16 X = 1 end end ->(x : LibFoo::MyEnum) { x }.call(LibFoo::MyEnum::X) CRYSTAL end it "codegens nilable proc type (1)" do run(<<-CRYSTAL).to_i.should eq(3) a = 1 == 2 ? nil : ->{ 3 } if a a.call else 4 end CRYSTAL end it "codegens nilable proc type (2)" do run(<<-CRYSTAL).to_i.should eq(4) a = 1 == 1 ? nil : ->{ 3 } if a a.call else 4 end CRYSTAL end it "codegens nilable proc type dispatch (1)" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x : -> U) forall U x.call end def foo(x : Nil) 0 end a = 1 == 1 ? (->{ 3 }) : nil foo(a) CRYSTAL end it "codegens nilable proc type dispatch (2)" do run(<<-CRYSTAL).to_i.should eq(0) def foo(x : -> U) forall U x.call end def foo(x : Nil) 0 end a = 1 == 1 ? nil : ->{ 3 } foo(a) CRYSTAL end it "builds proc type from fun" do codegen(<<-CRYSTAL) lib LibC fun foo : -> end x = LibC.foo x.call CRYSTAL end it "builds nilable proc type from fun" do codegen(<<-CRYSTAL) lib LibC fun foo : (->)? end x = LibC.foo if x x.call end CRYSTAL end it "assigns nil and proc to nilable proc type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize end def x=(@x : (-> Int32)?) end def x @x end end foo = Foo.new foo.x = nil foo.x = -> { 1 } z = foo.x if z z.call else 2 end CRYSTAL end it "allows invoking proc literal with smaller type" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end f = ->(x : Int32 | Nil) { x } f.call(1).to_i! CRYSTAL end it "does new on proc type" do run(<<-CRYSTAL).to_i.should eq(3) struct Proc def self.new(&block : self) block end end alias Func = Int32 -> Int32 a = 2 f = Func.new { |x| x &+ a } f.call(1) CRYSTAL end it "allows invoking a function with a subtype" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def x 1 end end class Bar < Foo def x 2 end end f = ->(foo : Foo) { foo.x } f.call Bar.new CRYSTAL end it "allows invoking a function with a subtype when defined as block spec" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def x 1 end end class Bar < Foo def x 2 end end def func(&block : Foo -> U) forall U block end f = func { |foo| foo.x } f.call Bar.new CRYSTAL end it "allows redefining fun" do run(<<-CRYSTAL).to_i.should eq(2) fun foo : Int32 1 end fun foo : Int32 2 end foo CRYSTAL end it "passes block to another function (bug: mangling of both methods was the same)" do run(<<-CRYSTAL).to_i.should eq(1) def foo(&block : ->) foo(block) end def foo(block) 1 end foo { } CRYSTAL end it "codegens proc with union type that returns itself" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 || 1.5 foo = ->(x : Int32 | Float64) { x } foo.call(a) foo.call(a).to_i! CRYSTAL end it "codegens issue with missing byval in proc literal inside struct" do run(<<-CRYSTAL).to_string.should eq("bar") require "prelude" struct Params def foo params = [] of {String} params << {"foo"} params << {"bar"} params.sort! { |x, y| x[0] <=> y[0] } params[0][0] end end Params.new.foo CRYSTAL end it "codegens proc that references struct (bug)" do run(<<-CRYSTAL).to_i.should_not eq(42) class Ref end class Context def initialize @x = Ref.new end def run @x.object_id end def it(&block) block.call end end struct Foo def initialize @x = 0 @y = 0 @z = 42 @w = 0 end end context = Context.new context.it do Foo.new end context.run CRYSTAL end it "codegens captured block that returns tuple" do codegen(<<-CRYSTAL) def foo(&block) block end block = foo do {0, 0, 42, 0} end block.call CRYSTAL end it "allows using proc arg name shadowing local variable" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 f = ->(a : String) { } a CRYSTAL end it "codegens proc that accepts array of type" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Foo def foo 1 end end class Bar < Foo def foo 2 end end def foo(&block : Array(Foo) -> Foo) block end block = foo { |elems| Bar.new } elems = [Bar.new, Foo.new] bar = block.call elems bar.foo CRYSTAL end it "gets proc to lib fun (#504)" do codegen(<<-CRYSTAL) lib LibFoo fun bar end ->LibFoo.bar CRYSTAL end it "gets proc to lib fun with parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(8)) #include int32_t foo(int32_t x, int32_t y) { return x + y; } C lib LibFoo fun foo(x : Int32, y : Int32) : Int32 end fn = ->LibFoo.foo(Int32, Int32) fn.call(3, 5) CRYSTAL end it "gets proc to lib fun with compatible parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(0x1235)) void *foo(void *x) { return (void *)((char *)x + 1); } C lib LibFoo fun foo(x : Void*) : Void* end x = Pointer(UInt8).new(0x1234) fn = ->LibFoo.foo(UInt8*) fn.call(x).address CRYSTAL end it "gets proc to lib fun with compatible `#to_unsafe` type" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(42)) #include int32_t foo(int32_t x) { return x * 2; } C lib LibFoo fun foo(x : Int32) : Int32 end class Foo def to_unsafe 21 end end fn = ->LibFoo.foo(Foo) fn.call(Foo.new) CRYSTAL end it "gets proc to variadic lib fun with parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(1110)) #include #include int32_t foo(int32_t n, ...) { va_list args; va_start(args, n); int32_t sum = 0; for (; n > 0; --n) sum += va_arg(args, int32_t); return sum; } C lib LibFoo fun foo(n : Int32, ...) : Int32 end fn = ->LibFoo.foo(Int32, Int32, Int32, Int32) fn.call(3, 10, 100, 1000) CRYSTAL end it "gets same pointer from proc pointers to lib fun with compatible types" do test_c(<<-C, <<-CRYSTAL, &.to_b.should be_true) void foo(void *x) { } C lib LibFoo fun foo(x : Void*) end a = ->LibFoo.foo b = ->LibFoo.foo(Void*) c = ->LibFoo.foo(UInt8*) a.pointer == b.pointer && a.pointer == c.pointer CRYSTAL end it "codegens proc to implicit self in constant (#647)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo def self.blah 1 end H = ->{ blah } end Foo::H.call CRYSTAL end it "passes proc as &->expr to method that yields" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield end foo &->{ 123 } CRYSTAL end it "mangles strings in such a way they don't conflict with funs (#1006)" do run(<<-CRYSTAL).to_i.should eq(123) a = :foo fun foo : Int32 123 end foo CRYSTAL end it "gets proc pointer using virtual type (#1337)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo 1 end end class Bar < Foo def foo 2 end end def foo(a : Foo) a.foo end bar = ->foo(Foo) bar.call(Bar.new) CRYSTAL end it "uses alias of proc with virtual type (#1347)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Class1 def foo 1 end end class Class2 < Class1 def foo 2 end end module Foo alias Callback = Class1 -> @@callbacks = Hash(String, Callback).new def self.add(name, &block : Callback) @@callbacks[name] = block end def self.call @@callbacks.each_value(&.call(Class2.new)) end end class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end Foo.add("foo") do |a| Global.x = a.foo end Foo.call Global.x CRYSTAL end it "doesn't crash on #2196" do run(<<-CRYSTAL).to_i.should eq(42) x = 42 z = if x.is_a?(Int32) x else y = x ->{ y } end z.is_a?(Int32) ? z : 0 CRYSTAL end it "accesses T in macros as a TupleLiteral" do run(<<-CRYSTAL).to_string.should eq("TupleLiteral") struct Proc def t {{ T.class_name }} end end ->(x : Int32) { 'a' }.t CRYSTAL end it "codegens proc in instance var initialize (#3016)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @f : -> Int32 = ->foo def self.foo 42 end end Foo.new.@f.call CRYSTAL end it "codegens proc of generic type" do codegen(<<-CRYSTAL) class Gen(T) end class Foo < Gen(Int32) end f = ->(x : Gen(Int32)) {} f.call(Foo.new) CRYSTAL end it "executes proc pointer on primitive" do run(<<-CRYSTAL).to_i.should eq(21) a = 1 f = ->a.&+(Int32) f.call(20) CRYSTAL end it "can pass Proc(T) to Proc(Nil) in type restriction (#8964)" do run(<<-CRYSTAL).to_i.should eq(2) def foo(x : Proc(Nil)) x end a = 1 proc = foo(->{ a = 2 }) proc.call a CRYSTAL end it "can assign proc that returns anything to proc that returns nil (#3655)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @block : -> Nil def initialize(@block) end def call @block.call end end a = 1 block = ->{ a = 2 } Foo.new(block).call a CRYSTAL end it "can assign proc that returns anything to proc that returns nil, using union type (#3655)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo @block : -> Nil def initialize(@block) end def call @block.call end end a = 1 block1 = ->{ a = 2 } block2 = ->{ a = 3; nil } Foo.new(block2 || block1).call a CRYSTAL end it "calls function pointer" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" fun foo(f : Int32 -> Int32) : Int32 f.call(1) end foo(->(x : Int32) { x &+ 1 }) CRYSTAL end it "casts from function pointer to proc" do codegen(<<-CRYSTAL) fun a(a : Void* -> Void*) Pointer(Proc((Void* -> Void*), Void*)).new(0_u64).value.call(a) end CRYSTAL end it "takes pointerof function pointer" do codegen(<<-CRYSTAL) fun a(a : Void* -> Void*) pointerof(a).value.call(Pointer(Void).new(0_u64)) end CRYSTAL end it "returns proc as function pointer inside top-level fun (#14691)" do run(<<-CRYSTAL, Int32).should eq(8) def raise(msg) while true end end fun add : Int32, Int32 -> Int32 ->(x : Int32, y : Int32) { x &+ y } end add.call(3, 5) CRYSTAL end it "returns ProcPointer inside top-level fun (#14691)" do run(<<-CRYSTAL, Int32).should eq(8) def raise(msg) while true end end fun foo(x : Int32) : Int32 x &+ 5 end fun bar : Int32 -> Int32 ->foo(Int32) end bar.call(3) CRYSTAL end it "raises if returning closure from top-level fun (#14691)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" @[Raises] fun foo(x : Int32) : -> Int32 -> { x } end begin foo(1) rescue true else false end CRYSTAL end it "closures var on ->var.call (#8584)" do run(<<-CRYSTAL).to_i.should eq(1) def bar(x) x end struct Foo def initialize @value = 1 end def value bar(@value) @value end end def get_proc_a foo = Foo.new ->foo.value end def get_proc_b foo = Foo.new ->{ foo.value } end proc_a = get_proc_a proc_b = get_proc_b proc_b.call proc_a.call CRYSTAL end it "saves receiver value of proc pointer `->var.foo`" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@foo : Int32) end def foo @foo end end var = Foo.new(1) proc = ->var.foo var = Foo.new(2) proc.call CRYSTAL end it "saves receiver value of proc pointer `->@ivar.foo`" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@foo : Int32) end def foo @foo end end class Test @ivar = Foo.new(1) def test proc = ->@ivar.foo @ivar = Foo.new(2) proc.call end end Test.new.test CRYSTAL end it "saves receiver value of proc pointer `->@@cvar.foo`" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def initialize(@foo : Int32) end def foo @foo end end class Test @@cvar = Foo.new(1) def self.test proc = ->@@cvar.foo @@cvar = Foo.new(2) proc.call end end Test.test CRYSTAL end it "doesn't crash when taking a proc pointer to a virtual type (#9823)" do run(<<-CRYSTAL, Proc(Int32, Int32, Int32)) abstract struct Parent abstract def work(a : Int32, b : Int32) def get ->work(Int32, Int32) end end struct Child1 < Parent def work(a : Int32, b : Int32) a &+ b end end struct Child2 < Parent def work(a : Int32, b : Int32) a &- b end end Child1.new.as(Parent).get CRYSTAL end it "doesn't crash when taking a proc pointer that multidispatches on the top-level (#3822)" do run(<<-CRYSTAL) class Foo def initialize(@proc : Proc(Bar, Nil)) end end module Bar end class Baz include Bar end def test(bar : Bar) if bar.is_a? Baz test bar end end def test(baz : Baz) end Foo.new(->test(Bar)) CRYSTAL end it "doesn't crash when taking a proc pointer that multidispatches on a module (#3822)" do run(<<-CRYSTAL) class Foo def initialize(@proc : Proc(Bar, Nil)) end end module Bar end class Baz include Bar end module Moo def self.test(bar : Bar) if bar.is_a? Baz test bar end end def self.test(baz : Baz) end end Foo.new(->Moo.test(Bar)) CRYSTAL end end ================================================ FILE: spec/compiler/codegen/regex_literal_spec.cr ================================================ require "../../spec_helper" describe "Code gen: regex literal spec" do it "works in a class variable (#10951)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" class Foo @@regex = /whatever/ def self.check_regex @@regex == /whatever/ end end Foo.check_regex CRYSTAL end end ================================================ FILE: spec/compiler/codegen/responds_to_spec.cr ================================================ require "../../spec_helper" describe "Codegen: responds_to?" do it "codegens responds_to? true for simple type" do run("1.responds_to?(:\"+\")").to_b.should be_true end it "codegens responds_to? false for simple type" do run("1.responds_to?(:foo)").to_b.should be_false end it "codegens responds_to? with union gives true" do run("(1 == 1 ? 1 : 'a').responds_to?(:\"+\")").to_b.should be_true end it "codegens responds_to? with union gives false" do run("(1 == 1 ? 1 : 'a').responds_to?(:\"foo\")").to_b.should be_false end it "codegens responds_to? with nilable gives true" do run("struct Nil; def foo; end; end; (1 == 1 ? nil : Reference.new).responds_to?(:foo)").to_b.should be_true end it "codegens responds_to? with nilable gives false because other type 1" do run("(1 == 1 ? nil : Reference.new).responds_to?(:foo)").to_b.should be_false end it "codegens responds_to? with nilable gives false because other type 2" do run("class Reference; def foo; end; end; (1 == 2 ? nil : Reference.new).responds_to?(:foo)").to_b.should be_true end it "codegens responds_to? with generic class (1)" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) def foo end end Foo(Int32).new.responds_to?(:foo) CRYSTAL end it "codegens responds_to? with generic class (2)" do run(<<-CRYSTAL).to_b.should be_false class Foo(T) def foo end end Foo(Int32).new.responds_to?(:bar) CRYSTAL end it "doesn't error if result is discarded (#14113)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo end end (Foo.new || "").responds_to?(:foo) 1 CRYSTAL end it "works with virtual type" do run(<<-CRYSTAL).to_b.should be_true class Foo end class Bar < Foo def foo 1 end end foo = Bar.new || Foo.new foo.responds_to?(:foo) CRYSTAL end it "works with two virtual types" do run(<<-CRYSTAL).to_b.should be_true class Foo end class Bar < Foo def foo 1 end end class Bar2 < Bar end class Other end class Sub < Other def foo 3 end end class Sub2 < Sub def foo 4 end end foo = Sub2.new || Bar.new || Bar2.new || Sub.new || Sub2.new foo.responds_to?(:foo) CRYSTAL end it "works with virtual class type (1) (#1926)" do run(<<-CRYSTAL).to_b.should be_true class Foo end class Bar < Foo def self.foo 1 end end foo = Bar || Foo foo.responds_to?(:foo) CRYSTAL end it "works with virtual class type (2) (#1926)" do run(<<-CRYSTAL).to_b.should be_false class Foo end class Bar < Foo def self.foo 1 end end foo = Foo || Bar foo.responds_to?(:foo) CRYSTAL end it "works with generic virtual superclass (1)" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) end class Bar < Foo(Int32) def foo 1 end end foo = Bar.new.as(Foo(Int32)) foo.responds_to?(:foo) CRYSTAL end it "works with generic virtual superclass (2)" do run(<<-CRYSTAL).to_b.should be_true class Foo(T) end class Bar(T) < Foo(T) def foo 1 end end foo = Bar(Int32).new.as(Foo(Int32)) foo.responds_to?(:foo) CRYSTAL end it "works with module" do run(<<-CRYSTAL).to_b.should be_true module Moo end class Foo include Moo def foo 1 end end class Bar include Moo def foo 1 end end ptr = Pointer(Moo).malloc(1_u64) ptr.value = Bar.new ptr.value = Foo.new moo = ptr.value moo.responds_to?(:foo) CRYSTAL end it "works with generic virtual module (1)" do run(<<-CRYSTAL).to_b.should be_true module Foo(T) end class Bar include Foo(Int32) def foo 1 end end foo = Bar.new.as(Foo(Int32)) foo.responds_to?(:foo) CRYSTAL end it "works with generic virtual module (2) (#8334)" do run(<<-CRYSTAL).to_b.should be_true module Foo(T) end class Bar(T) include Foo(T) def foo 1 end end foo = Bar(Int32).new.as(Foo(Int32)) foo.responds_to?(:foo) CRYSTAL end it "does for generic instance type metaclass (#4353)" do run(<<-CRYSTAL).to_b.should be_true class MyGeneric(T) def self.hallo 1 end end MyGeneric(String).responds_to? :hallo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/return_spec.cr ================================================ require "../../spec_helper" describe "Code gen: return" do it "codegens return" do run("def foo; return 1; end; foo").to_i.should eq(1) end it "codegens return followed by another expression" do run("def foo; return 1; 2; end; foo").to_i.should eq(1) end it "codegens return inside if" do run("def foo; if 1 == 1; return 1; end; 2; end; foo").to_i.should eq(1) end it "return from function with union type" do run("struct Char; def to_i!; 2; end; end; def foo; return 1 if 1 == 1; 'a'; end; foo.to_i!").to_i.should eq(1) end it "return union" do run("struct Char; def to_i!; 2; end; end; def foo; 1 == 2 ? return 1 : return 'a'; end; foo.to_i!").to_i.should eq(2) end it "return from function with nilable type" do run(%(def foo; return Reference.new if 1 == 1; end; foo.nil?)).to_b.should be_false end it "return from function with nilable type 2" do run(%(def foo; return Reference.new if 1 == 1; end; foo.nil?)).to_b.should be_false end it "returns empty from function" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil; def to_i!; 0; end; end def foo(x) return if x == 1 1 end foo(2).to_i! CRYSTAL end it "codegens bug with return if true" do run(<<-CRYSTAL).to_b.should be_true def bar return if true 1 end bar.is_a?(Nil) CRYSTAL end it "codegens assign with if with two returns" do run(<<-CRYSTAL).to_i.should eq(2) def test a = 1 ? return 2 : return 3 end test CRYSTAL end it "doesn't crash when method returns nil and can be inlined" do codegen(<<-CRYSTAL) def foo : Nil 1 end foo CRYSTAL end it "returns in var assignment (#3364)" do run(<<-CRYSTAL).to_i.should eq(123) def bar a = nil || return 123 end bar CRYSTAL end it "forms a tuple from multiple return values" do run(<<-CRYSTAL).to_i.should eq(2) def foo return 5, 3 end v = foo v[0] &- v[1] CRYSTAL end it "flattens splats inside multiple return values" do run(<<-CRYSTAL).to_i.should eq(18) def foo return 1, *{3, 9}, 27 end v = foo v[3] &- v[2] CRYSTAL end end ================================================ FILE: spec/compiler/codegen/sizeof_spec.cr ================================================ require "../../spec_helper" describe "Code gen: sizeof" do it "gets sizeof int" do run("sizeof(Int32)").to_i.should eq(4) end it "gets sizeof struct" do run(<<-CRYSTAL).to_i.should eq(12) struct Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) sizeof(Foo) CRYSTAL end it "gets sizeof class" do # A class is represented as a pointer to its data run(<<-CRYSTAL).to_i.should eq(sizeof(Void*)) class Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) sizeof(Foo) CRYSTAL end it "gets sizeof union" do size = run(<<-CRYSTAL).to_i sizeof(Int32 | Float64) CRYSTAL # This union is represented as: # # struct { # 4 bytes, # for the type id # 8 bytes, # for the largest size between Int32 and Float64 # } # # But in 64 bits structs are aligned to 8 bytes, so it'll actually # be struct { 8 bytes, 8 bytes }. # # In 32 bits structs are aligned to 4 bytes, so it remains the same. {% if flag?(:bits64) %} size.should eq(16) {% else %} size.should eq(12) {% end %} end it "gets instance_sizeof class" do run(<<-CRYSTAL).to_i.should eq(16) class Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) instance_sizeof(Foo) CRYSTAL end it "gets instance_sizeof a generic type with type vars" do run(<<-CRYSTAL).to_i.should eq(8) class Foo(T) def initialize(@x : T) end end instance_sizeof(Foo(Int32)) CRYSTAL end it "gets sizeof Void" do # Same as the size of a byte, because doing # `Pointer(Void).malloc` must work like `Pointer(UInt8).malloc` run("sizeof(Void)").to_i.should eq(1) end it "gets sizeof NoReturn" do # NoReturn can't hold anything run("sizeof(NoReturn)").to_i.should eq(0) end it "gets sizeof Nil (#7644)" do # Nil can't hold anything run("sizeof(Nil)").to_i.should eq(0) end it "gets sizeof Bool (#8272)" do run("sizeof(Bool)").to_i.should eq(1) end it "can use sizeof in type argument (1)" do run(<<-CRYSTAL).to_i.should eq(4) struct StaticArray def size N end end x = uninitialized UInt8[sizeof(Int32)] x.size CRYSTAL end it "can use sizeof in type argument (2)" do run(<<-CRYSTAL).to_i.should eq(8) struct StaticArray def size N end end x = uninitialized UInt8[sizeof(Float64)] x.size CRYSTAL end it "can use sizeof of virtual type" do size = run(<<-CRYSTAL).to_i class Foo @x = 1 end class Bar < Foo @y = 2 end foo = Bar.new.as(Foo) sizeof(typeof(foo)) CRYSTAL {% if flag?(:bits64) %} size.should eq(8) {% else %} size.should eq(4) {% end %} end it "can use instance_sizeof of virtual type" do run(<<-CRYSTAL).to_i.should eq(12) class Foo @x = 1 end class Bar < Foo @y = 2 end class Baz < Bar @z = 2 end bar = Baz.new.as(Bar) instance_sizeof(typeof(bar)) CRYSTAL end it "can use instance_sizeof in type argument" do run(<<-CRYSTAL).to_i.should eq(12) struct StaticArray def size N end end class Foo def initialize @x = 1 @y = 1 end end x = uninitialized UInt8[instance_sizeof(Foo)] x.size CRYSTAL end it "returns correct sizeof for abstract struct (#4319)" do size = run(<<-CRYSTAL).to_i abstract struct Entry end struct FooEntry < Entry def initialize @uid = "" end end struct BarEntry < Entry def initialize @uid = "" end end sizeof(Entry) CRYSTAL size.should eq(16) end it "doesn't precompute sizeof of abstract struct (#7741)" do run(<<-CRYSTAL).to_i.should eq(16) abstract struct Base end struct Foo(T) < Base def initialize(@x : T) end end z = sizeof(Base) Foo({Int32, Int32, Int32, Int32}) z CRYSTAL end it "doesn't precompute sizeof of module (#7741)" do run(<<-CRYSTAL).to_i.should eq(16) module Base end struct Foo(T) include Base def initialize(@x : T) end end z = sizeof(Base) Foo({Int32, Int32, Int32, Int32}) z CRYSTAL end describe "alignof" do it "gets alignof primitive types" do run("alignof(Int32)").to_i.should eq(4) run("alignof(Void)").to_i.should eq(1) run("alignof(NoReturn)").to_i.should eq(1) run("alignof(Nil)").to_i.should eq(1) run("alignof(Bool)").to_i.should eq(1) end it "gets alignof struct" do run(<<-CRYSTAL).to_i.should eq(4) struct Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) alignof(Foo) CRYSTAL end it "gets alignof class" do # pointer size and alignment should be identical run(<<-CRYSTAL).to_i.should eq(sizeof(Void*)) class Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) alignof(Foo) CRYSTAL end it "gets alignof union" do run("alignof(Int32 | Int8)").to_i.should eq(8) run("alignof(Int32 | Int64)").to_i.should eq(8) end it "alignof mixed union is not less than alignof its variant types" do # NOTE: `alignof(Int128) == 16` is not guaranteed run("alignof(Int32 | Int128) >= alignof(Int128)").to_b.should be_true end end describe "instance_alignof" do it "gets instance_alignof class" do run(<<-CRYSTAL).to_i.should eq(4) class Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) instance_alignof(Foo) CRYSTAL run(<<-CRYSTAL).to_i.should eq(8) class Foo def initialize(@x : Int8, @y : Int64, @z : Int16) end end Foo.new(1, 2, 3) instance_alignof(Foo) CRYSTAL run(<<-CRYSTAL).to_i.should eq(4) class Foo end Foo.new instance_alignof(Foo) CRYSTAL end it "gets instance_alignof a generic type with type vars" do run(<<-CRYSTAL).to_i.should eq(4) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int32)) CRYSTAL run(<<-CRYSTAL).to_i.should eq(8) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int64)) CRYSTAL run(<<-CRYSTAL).to_i.should eq(4) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int8)) CRYSTAL end end end ================================================ FILE: spec/compiler/codegen/special_vars_spec.cr ================================================ require "../../spec_helper" describe "Codegen: special vars" do ["$~", "$?"].each do |name| it "codegens #{name}" do run(<<-CRYSTAL).to_string.should eq("hey") class Object; def not_nil!; self; end; end def foo(z) #{name} = "hey" end foo(2) #{name} CRYSTAL end it "codegens #{name} with nilable (1)" do run(<<-CRYSTAL).to_string.should eq("ouch") require "prelude" def foo if 1 == 2 #{name} = "foo" end end foo begin #{name} rescue ex "ouch" end CRYSTAL end it "codegens #{name} with nilable (2)" do run(<<-CRYSTAL).to_string.should eq("foo") require "prelude" def foo if 1 == 1 #{name} = "foo" end end foo begin #{name} rescue ex "ouch" end CRYSTAL end end it "codegens $~ two levels" do run(<<-CRYSTAL).to_string.should eq("hey") class Object; def not_nil!; self; end; end def foo $? = "hey" end def bar $? = foo $? end bar $? CRYSTAL end it "works lazily" do run(<<-CRYSTAL).to_string.should eq("bar") require "prelude" class Foo getter string def initialize(@string : String) end end def bar(&block : Foo -> _) block end block = bar do |foo| case foo.string when /foo-(.+)/ $1 else "baz" end end block.call(Foo.new("foo-bar")) CRYSTAL end it "codegens in block" do run(<<-CRYSTAL).to_string.should eq("hey") require "prelude" class Object; def not_nil!; self; end; end def foo $~ = "hey" yield end a = nil foo do a = $~ end a.not_nil! CRYSTAL end it "codegens in block with nested block" do run(<<-CRYSTAL).to_string.should eq("hey") require "prelude" class Object; def not_nil!; self; end; end def bar yield end def foo bar do $~ = "hey" yield end end a = nil foo do a = $~ end a.not_nil! CRYSTAL end it "codegens after block" do run(<<-CRYSTAL).to_string.should eq("hey") require "prelude" class Object; def not_nil!; self; end; end def foo $~ = "hey" yield end a = nil foo {} $~ CRYSTAL end it "codegens after block 2" do run(<<-CRYSTAL).to_string.should eq("bye") class Object; def not_nil!; self; end; end def baz $~ = "bye" end def foo baz yield $~ end foo do end CRYSTAL end it "codegens with default argument" do run(<<-CRYSTAL).to_string.should eq("bye") class Object; def not_nil!; self; end; end def baz(x = 1) $~ = "bye" end baz $~ CRYSTAL end it "preserves special vars in macro expansion with call with default arguments (#824)" do run(<<-CRYSTAL).to_string.should eq("yes") class Object; def not_nil!; self; end; end def bar(x = 0) $~ = "yes" end macro foo bar $~ end foo CRYSTAL end it "allows with primitive" do run(<<-CRYSTAL).to_i.should eq(123) class Object; def not_nil!; self; end; end def foo $~ = 123 end foo v = $~ v || 456 CRYSTAL end it "allows with struct" do run(<<-CRYSTAL).to_i.should eq(123) class Object; def not_nil!; self; end; end struct Foo def initialize(@x : Int32) end def x @x end end def foo $~ = Foo.new(123) end foo v = $~ if v v.x else 456 end CRYSTAL end it "preserves special vars if initialized inside block (#2194)" do run(<<-CRYSTAL).to_string.should eq("foo") class Object; def not_nil!; self; end; end def foo $~ = "foo" end def bar yield end bar do foo end v = $~ if v v else "bar" end CRYSTAL end end ================================================ FILE: spec/compiler/codegen/splat_spec.cr ================================================ require "../../spec_helper" describe "Code gen: splat" do it "splats" do run(<<-CRYSTAL).to_i.should eq(3) struct Tuple def size; {{T.size}}; end end def foo(*args) args.size end foo 1, 1, 1 CRYSTAL end it "splats with another arg" do run(<<-CRYSTAL).to_i.should eq(12) struct Tuple def size; {{T.size}}; end end def foo(x, *args) x &+ args.size end foo 10, 1, 1 CRYSTAL end it "splats on call" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x, y) x &+ y end tuple = {1, 2} foo *tuple CRYSTAL end it "splats without args" do run(<<-CRYSTAL).to_i.should eq(0) struct Tuple def size; {{T.size}}; end end def foo(*args) args.size end foo CRYSTAL end it "splats with default value" do run(<<-CRYSTAL).to_i.should eq(100) struct Tuple def size; {{T.size}}; end end def foo(x = 100, *args) x &+ args.size end foo CRYSTAL end it "splats with default value (2)" do run(<<-CRYSTAL).to_i.should eq(110) struct Tuple def size; {{T.size}}; end end def foo(x, y = 100, *args) x &+ y &+ args.size end foo 10 CRYSTAL end it "splats with default value (3)" do run(<<-CRYSTAL).to_i.should eq(32) struct Tuple def size; {{T.size}}; end end def foo(x, y = 100, *args) x &+ y &+ args.size end foo 10, 20, 30, 40 CRYSTAL end it "splats in initialize" do run(<<-CRYSTAL).to_i.should eq(3) class Foo @x : Int32 @y : Int32 def initialize(*args) @x, @y = args end def x @x end def y @y end end foo = Foo.new 1, 2 foo.x &+ foo.y CRYSTAL end it "does #2407" do codegen(<<-CRYSTAL) lib LibC fun exit(Int32) : NoReturn end def some yield(1 || (LibC.exit(1); "")) end def foo(*objects) bar *objects end def bar(objects) end some do |value| foo value end CRYSTAL end it "evaluates splat argument just once (#2677)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def data Global.x &+= 1 {Global.x, Global.x, Global.x} end def test(x, y, z) x &+ y &+ z end v = test(*data) Global.x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/ssa_spec.cr ================================================ require "../../spec_helper" describe "Code gen: ssa" do it "codegens a redefined var" do run(<<-CRYSTAL).to_i.should eq(1) a = 1.5 a = 1 a CRYSTAL end it "codegens a redefined var inside method" do run(<<-CRYSTAL).to_i.should eq(1) def foo a = 1.5 a = 1 a end foo CRYSTAL end it "codegens a redefined var inside method with argument" do run(<<-CRYSTAL).to_i.should eq(1) def foo(a) a = 1 a end foo 1.5 CRYSTAL end it "codegens declaration of var inside then when false" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil def to_i! 0 end end if 1 == 2 b = 2 end b.to_i! CRYSTAL end it "codegens declaration of var inside then when true" do run(<<-CRYSTAL).to_i.should eq(2) struct Nil def to_i! 0 end end if 1 == 1 b = 2 end b.to_i! CRYSTAL end it "codegens a var that is re-assigned in a block" do run(<<-CRYSTAL).to_i.should eq(10) struct Char def to_i! 10 end end def foo yield end a = 1 foo do a = 'a' end a.to_i! CRYSTAL end it "codegens a var that is re-assigned in a block (1)" do run(<<-CRYSTAL).to_i.should eq(10) struct Char def to_i! 10 end end a = 1 while a.to_i! == 1 a = 'a' end a.to_i! CRYSTAL end it "codegens a var that is re-assigned in a block (2)" do run(<<-CRYSTAL).to_i.should eq(1) struct Char def to_i! 10 end end a = 1 while 1 == 2 a = 'a' end a.to_i! CRYSTAL end it "codegens a var that is declared in a block (1)" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil def to_i! 0 end end while 1 == 2 a = 1 end a.to_i! CRYSTAL end it "codegens a var that is declared in a block (2)" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end b = 1 while b == 1 a = 1 b = 2 end a.to_i! CRYSTAL end it "codegens ssa bug with if/else on var" do run(<<-CRYSTAL).to_i.should eq(3) a = 1 || nil if a && false b = 2 elsif a b = 3 else b = 4 end b CRYSTAL end it "codegens ssa bug (1)" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end index = nil if index a = index 1 else if 1 == 1 index = 1 else 1 end a = index 1 end a.to_i! CRYSTAL end it "codegens ssa bug (2)" do # This shows a bug where a block variable (coconio in this case) # wasn't reset to nil before each block iteration. run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end def foo i = 1 while i <= 3 yield i i &+= 1 end end a = 0 foo do |x| coconio = x if x == 1 a &+= coconio.to_i! end a CRYSTAL end end ================================================ FILE: spec/compiler/codegen/struct_spec.cr ================================================ require "../../spec_helper" describe "Code gen: struct" do it "creates structs" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo end f = Foo.allocate 1 CRYSTAL end it "creates structs with instance var" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def x @x end end f = Foo.new(1) f.x CRYSTAL end it "assigning a struct makes a copy (1)" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def initialize(@x : Int32) end def x @x end def x=(@x) end end f = Foo.new(1) g = f g.x = 2 g.x CRYSTAL end it "assigning a struct makes a copy (2)" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def x @x end def x=(@x) end end f = Foo.new(1) g = f g.x = 2 f.x CRYSTAL end it "passes a struct as a parameter makes a copy" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def x @x end def x=(@x) end end def foo(f) f.x = 2 end f = Foo.new(1) foo(f) f.x CRYSTAL end it "passes a generic struct as a parameter makes a copy" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo(T) def initialize(@x : T) end def x @x end def x=(@x) end end def foo(f) f.x = 2 end f = Foo(Int32).new(1) foo(f) f.x CRYSTAL end it "returns struct as a copy" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def initialize(@x : Int32) end def x @x end def x=(@x) end end def foo(f) f.x = 2 f end f = Foo.new(1) g = foo(f) g.x CRYSTAL end it "creates struct in def" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def x @x end end def foo Foo.new(1) end foo.x CRYSTAL end it "declares const struct" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" struct Foo def initialize(@x : Int32) end def x @x end end FOO = Foo.new(1) FOO.x CRYSTAL end it "uses struct in if" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" struct Foo def initialize(@x : Int32) end def x @x end end FOO = Foo.new(1) if 1 == 2 foo = Foo.new(1) else foo = FOO end foo.x CRYSTAL end it "uses nilable struct" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo end f = Foo.new || nil f.nil? ? 1 : 2 CRYSTAL end it "returns self" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def initialize(@x) end def foo @x = 2 return self end def x @x end end f = Foo.new(1) g = f.foo g.x CRYSTAL end it "returns self with block" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def initialize(@x) end def foo @x = 2 yield 1 self end def x @x end end f = Foo.new(1) g = f.foo { } g.x CRYSTAL end it "does phi of struct" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def initialize(@x : Int32) end def x @x end end x = if 1 == 2 Foo.new(2) else Foo.new(1) end x.x CRYSTAL end it "allows assigning to struct argument (bug)" do run(<<-CRYSTAL).to_i.should eq(2) struct Foo def bar 2 end end def foo(x) x = x.bar end foo(Foo.new) CRYSTAL end it "codegens struct assigned to underscore (#1842)" do run(<<-CRYSTAL).to_i.should eq(123) struct Foo def initialize @value = 123 end def value @value end end def foo _ = Foo.new end foo.value CRYSTAL end it "codegens virtual struct" do run(<<-CRYSTAL).to_i.should eq(1) abstract struct Foo end struct Bar < Foo def initialize @x = 1 end def x @x end end struct Baz < Foo def initialize @x = 2 end def x @x end end foo = Bar.new || Baz.new foo.x CRYSTAL end it "codegens virtual struct with pointer" do run(<<-CRYSTAL).to_i.should eq(1) abstract struct Foo end struct Bar < Foo def initialize @x = 1 end def x @x end end struct Baz < Foo def initialize @x = 2 end def x @x end end ptr = Pointer(Foo).malloc(1_u64) ptr.value = Baz.new ptr.value = Bar.new ptr.value.x CRYSTAL end it "codegens virtual struct metaclass (#2551) (1)" do run(<<-CRYSTAL).to_i.should eq(42) abstract struct Foo def initialize @x = 21 end def x a = @x a end end struct Bar < Foo def initialize @x = 42 end end struct Baz < Foo end Bar.new.as(Foo).x CRYSTAL end it "codegens virtual struct metaclass (#2551) (2)" do run(<<-CRYSTAL).to_i.should eq(42) abstract struct Foo def initialize @x = 21 end end struct Bar < Foo def initialize @x = 42 end end struct Baz < Foo end Bar.new.as(Foo).@x CRYSTAL end it "codegens virtual struct metaclass (#2551) (3)" do run(<<-CRYSTAL).to_i.should eq(42) abstract struct Foo def initialize @x = 21 end def x @x end end struct Bar < Foo def initialize @x = 42 end end struct Baz < Foo end Bar.new.as(Foo).x CRYSTAL end it "codegens virtual struct metaclass (#2551) (4)" do run(<<-CRYSTAL).to_i.should eq(42) require "prelude" abstract struct Foo def initialize @x = 21 end def x a = @x a end end struct Bar < Foo def initialize @x = 42 end end struct Baz < Foo end (Bar || Baz).new.x CRYSTAL end it "mutates a virtual struct" do run(<<-CRYSTAL).to_i.should eq(84) abstract struct Foo def initialize @x = 21 end def x=(@x) end def x @x end end struct Bar < Foo def initialize @x = 42 end end struct Baz < Foo end foo = Bar.new.as(Foo) foo.x = 84 foo.x CRYSTAL end it "codegens virtual structs union (1)" do run(<<-CRYSTAL).to_i.should eq(42) abstract struct Foo end struct Bar < Foo def initialize @x = 42 end def x @x end end abstract struct Foo2 end struct Bar2 < Foo2 def initialize @x = 84 end def x @x end end foo = Bar.new.as(Foo) foo2 = Bar2.new.as(Foo2) f = foo || foo2 f.x CRYSTAL end it "codegens virtual structs union (2)" do run(<<-CRYSTAL).to_i.should eq(84) abstract struct Foo end struct Bar < Foo def initialize @x = 42 end def x @x end end abstract struct Foo2 end struct Bar2 < Foo2 def initialize @x = 84 end def x @x end end foo = Bar.new.as(Foo) foo2 = Bar2.new.as(Foo2) f = foo2 || foo f.x CRYSTAL end it "can cast virtual struct to specific struct" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" abstract struct Foo end struct Bar < Foo def foo 1 end end struct Baz < Foo def foo 2 end end x = Bar.new || Baz.new x.as(Bar).foo CRYSTAL end it "casts virtual struct to base type, only one subclass (#2885)" do run(<<-CRYSTAL).to_string.should eq("1") abstract struct Entry def initialize(@uid : String, @country : String) end def uid @uid end end struct MyEntry < Entry end entry = MyEntry.new("1", "GER") entry.as(Entry).uid CRYSTAL end it "can call new on abstract struct with single child (#7309)" do codegen(<<-CRYSTAL, inject_primitives: false) require "prelude" abstract struct Foo @x = 1 end struct A < Foo @y = 2 end A.as(Foo.class).new CRYSTAL end end ================================================ FILE: spec/compiler/codegen/super_spec.cr ================================================ require "../../spec_helper" describe "Codegen: super" do it "codegens super without arguments" do run("class Foo; def foo; 1; end; end; class Bar < Foo; def foo; super; end; end; Bar.new.foo").to_i.should eq(1) end it "codegens super without arguments but parent has arguments" do run("class Foo; def foo(x); x &+ 1; end; end; class Bar < Foo; def foo(x); super; end; end; Bar.new.foo(1)").to_i.should eq(2) end it "codegens super without arguments and instance variable" do run("class Foo; def foo; @x = 1; end; end; class Bar < Foo; def foo; super; end; end; Bar.new.foo").to_i.should eq(1) end it "codegens super that calls subclass method" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo bar end def bar 1 end end class Bar < Foo def foo super end def bar 2 end end b = Bar.new b.foo CRYSTAL end it "codegens super that calls subclass method 2" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo self.bar end def bar 1 end end class Bar < Foo def foo super end def bar 2 end end b = Bar.new b.foo CRYSTAL end it "codegens super that calls subclass method 3" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo self.bar end def bar 1 end end class Bar < Foo def foo super end def bar 2 end end b = Foo.new || Bar.new b.foo CRYSTAL end it "codegens super that calls subclass method 4" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo self.bar end def bar 1 end end class Bar < Foo def foo super end def bar 2 end end b = Bar.new || Foo.new b.foo CRYSTAL end it "codegens super that calls subclass method 5" do run(<<-CRYSTAL).to_i.should eq(2) module Mod def add_def another end end abstract class ClassType include Mod def add_def super end end class NonGenericClassType < ClassType end class PrimitiveType < ClassType def another 2 end end class IntegerType < PrimitiveType def another 3 end end c = PrimitiveType.new || IntegerType.new c.add_def CRYSTAL end it "codegens super that calls subclass method 6" do run(<<-CRYSTAL).to_i.should eq(3) module Mod def add_def another end end abstract class ClassType include Mod def add_def super end end class NonGenericClassType < ClassType end class PrimitiveType < ClassType def another 2 end end class IntegerType < PrimitiveType def another 3 end end c = IntegerType.new || PrimitiveType.new c.add_def CRYSTAL end it "codegens super inside closure" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end def foo @x end end class Bar < Foo def foo ->{ super } end end f = Bar.new(1).foo f.call CRYSTAL end it "codegens super inside closure forwarding args" do run(<<-CRYSTAL).to_i.should eq(6) class Foo def initialize(@x : Int32) end def foo(z) z &+ @x end end class Bar < Foo def foo(z) ->(x : Int32) { x &+ super } end end f = Bar.new(1).foo(2) f.call(3) CRYSTAL end it "build super on generic class (bug)" do codegen(<<-CRYSTAL) class Base def foo(x) 1.5 end end class Foo(T) < Base def foo super(1) end end Foo(Int32).new.foo CRYSTAL end it "calls super in module method (#556)" do run(<<-CRYSTAL).to_i.should eq(1) class Parent def a 1 end end module Mod def a super end end class Child < Parent include Mod end Child.new.a CRYSTAL end it "calls super in generic module method" do run(<<-CRYSTAL).to_i.should eq(1) class Parent def a 1 end end module Mod(T) def a super end end class Child < Parent include Mod(Int32) end Child.new.a CRYSTAL end it "does super in virtual type including module" do run(<<-CRYSTAL).to_i.should eq(123) module Bar def bar 123 end end module Foo include Bar def bar super end end class Base include Foo end class Child < Base end (Base.new || Child.new).bar CRYSTAL end it "doesn't invoke super twice in inherited generic types (#942)" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end abstract class Foo end class Bar(T) < Foo def initialize Global.x &+= 1 super end end class Baz(T) < Bar(T) end Baz(Int8).new Global.x CRYSTAL end it "calls super in metaclass (#1522)" do # We include the prelude so this is codegened for real, because that's where the issue lies run(<<-CRYSTAL).to_i.should eq(5) require "prelude" class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end class Base def self.foo Global.x += 1 end end class One < Base def self.foo Global.x += 3 super end end Base.foo One.foo CRYSTAL end it "calls super with dispatch (#2318)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def foo(x : Int32) x end def foo(x : Float64) x end end class Bar < Foo def foo(obj) super(obj) end end z = Bar.new.foo(3 || 2.5) z.to_i! CRYSTAL end it "calls super from virtual metaclass type (#2841)" do run(<<-CRYSTAL) abstract class Foo def self.bar(x : Bool) x end end class Bar < Foo def self.bar(x : Bool) super end end class Baz < Foo def self.bar(x : Bool) super end end (Foo || Bar).bar(true) CRYSTAL end it "calls super on an object (#10004)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @foo = 42 def super @foo end end Foo.new.super CRYSTAL end end ================================================ FILE: spec/compiler/codegen/target_spec.cr ================================================ require "spec" require "compiler/requires" private alias Target = Crystal::Codegen::Target describe Crystal::Codegen::Target do it "parses incomplete triples" do target = Target.new("x86_64-linux-gnu") target.to_s.should eq("x86_64-unknown-linux-gnu") target.pointer_bit_width.should eq(64) target.linux?.should be_true target.unix?.should be_true target.gnu?.should be_true end it "normalizes triples" do Target.new("i686-unknown-linux-gnu").to_s.should eq("i386-unknown-linux-gnu") Target.new("amd64-unknown-openbsd").to_s.should eq("x86_64-unknown-openbsd") Target.new("arm64-apple-darwin20.2.0").to_s.should eq("aarch64-apple-darwin20.2.0") Target.new("x86_64-suse-linux").to_s.should eq("x86_64-suse-linux-gnu") end it "parses freebsd version" do Target.new("x86_64-unknown-linux-gnu").freebsd_version.should be_nil Target.new("x86_64-unknown-freebsd8.0").freebsd_version.should eq(8) Target.new("x86_64-unknown-freebsd11.0").freebsd_version.should eq(11) end end ================================================ FILE: spec/compiler/codegen/thread_local_spec.cr ================================================ {% skip_file if flag?(:openbsd) || (flag?(:win32) && flag?(:gnu)) %} require "../../spec_helper" describe "Codegen: thread local" do it "works with class variables" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" class Foo @[ThreadLocal] @@var = 123 def self.var @@var end def self.var=(@@var) end end Thread.new { Foo.var = 456 }.join Foo.var CRYSTAL end it "works with class variable in main thread" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" class Foo @[ThreadLocal] @@a = 123 def self.a @@a end end Foo.a CRYSTAL end it "compiles with class variable referenced from initializer" do run(<<-CRYSTAL) require "prelude" class Foo @[ThreadLocal] @@x : Foo? @@x = nil def self.x @@x ||= new end def initialize Foo.x end end 0 CRYSTAL end end ================================================ FILE: spec/compiler/codegen/tuple_spec.cr ================================================ require "../../spec_helper" describe "Code gen: tuple" do it "codegens tuple [0]" do run("{1, true}[0]").to_i.should eq(1) end it "codegens tuple [1]" do run("{1, true}[1]").to_b.should be_true end it "codegens tuple [1] (2)" do run("{true, 3}[1]").to_i.should eq(3) end it "codegens tuple [0]?" do run("{42, 'a'}[0]? || 84").to_i.should eq(42) end it "codegens tuple [1]?" do run("{'a', 42}[1]? || 84").to_i.should eq(42) end it "codegens tuple [2]?" do run("{'a', 42}[2]? || 84").to_i.should eq(84) end it "codegens tuple metaclass [0]" do run("Tuple(Int32, Char)[0].is_a?(Int32.class)").to_b.should be_true end it "codegens tuple metaclass [1]" do run("Tuple(Int32, Char)[1].is_a?(Char.class)").to_b.should be_true end it "codegens tuple metaclass [2]?" do run("Tuple(Int32, Char)[2]?.nil?").to_b.should be_true end it "codegens tuple [0..0]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..0] val.is_a?(Tuple(Int32)) && val[0] == 1 CRYSTAL end it "codegens tuple [0..1]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..1] val.is_a?(Tuple(Int32, Bool)) && val[0] == 1 && val[1] == true CRYSTAL end it "codegens tuple [0..2]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..2] val.is_a?(Tuple(Int32, Bool)) && val[0] == 1&& val[1] == true CRYSTAL end it "codegens tuple [1..1]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[1..1] val.is_a?(Tuple(Bool)) && val[0] == true CRYSTAL end it "codegens tuple [1..0]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} def empty(*args) args end {1, true}[1..0].is_a?(typeof(empty)) CRYSTAL end it "codegens tuple [2..2]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} def empty(*args) args end {1, true}[2..2].is_a?(typeof(empty)) CRYSTAL end it "codegens tuple [0..0]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..0]? val.is_a?(Tuple(Int32)) && val[0] == 1 CRYSTAL end it "codegens tuple [0..1]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..1]? val.is_a?(Tuple(Int32, Bool)) && val[0] == 1 && val[1] == true CRYSTAL end it "codegens tuple [0..2]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[0..2]? val.is_a?(Tuple(Int32, Bool)) && val[0] == 1&& val[1] == true CRYSTAL end it "codegens tuple [1..1]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} val = {1, true}[1..1]? val.is_a?(Tuple(Bool)) && val[0] == true CRYSTAL end it "codegens tuple [1..0]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} def empty(*args) args end {1, true}[1..0]?.is_a?(typeof(empty)) CRYSTAL end it "codegens tuple [2..2]?" do run(<<-CRYSTAL).to_b.should be_true #{range_new} def empty(*args) args end {1, true}[2..2]?.is_a?(typeof(empty)) CRYSTAL end it "codegens tuple [3..2]?" do run("#{range_new}; {1, true}[3..2]?.nil?").to_b.should be_true end it "codegens tuple [-3..2]?" do run("#{range_new}; {1, true}[-3..2]?.nil?").to_b.should be_true end it "codegens tuple metaclass [0..0]" do run("#{range_new}; Tuple(Int32, Char)[0..0].is_a?(Tuple(Int32).class)").to_b.should be_true end it "codegens tuple metaclass [0..1]" do run("#{range_new}; Tuple(Int32, Char)[0..1].is_a?(Tuple(Int32, Char).class)").to_b.should be_true end it "codegens tuple metaclass [1..0]" do run(<<-CRYSTAL).to_b.should be_true #{range_new} def empty(*args) args.class end Tuple(Int32, Char)[1..0].is_a?(typeof(empty)) CRYSTAL end it "codegens tuple metaclass [3..2]?" do run("#{range_new}; Tuple(Int32, Char)[3..2]?.nil?").to_b.should be_true end it "codegens splats inside tuples" do run(<<-CRYSTAL).to_i.should eq(2 + 4 + 32 + 128) x = {1, *{2, 4}, 8, *{16, 32, 64}, 128} x[1] &+ x[2] &+ x[5] &+ x[7] CRYSTAL end it "passed tuple to def" do run(<<-CRYSTAL).to_i.should eq(2) def foo(t) t[1] end foo({1, 2, 3}) CRYSTAL end it "accesses T and creates instance from it" do run(<<-CRYSTAL).to_i.should eq(2) struct Tuple def type_args T end end class Foo def initialize(@x : Int32) end def x @x end end t = {Foo.new(1)} f = t.type_args[0].new(2) f.x CRYSTAL end it "allows malloc pointer of tuple" do run(<<-CRYSTAL).to_i.should eq(3) struct Pointer def self.malloc(size : Int) malloc(size.to_u64!) end end def foo(x : T) forall T p = Pointer(T).malloc(1) p.value = x p end p = foo({1, 2}) p.value[0] &+ p.value[1] CRYSTAL end it "codegens tuple union (bug because union size was computed incorrectly)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" x = 1 == 1 ? {1, 1, 1} : {1} i = 2 x[i] CRYSTAL end it "codegens tuple class" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize(@x : Int32) end def x @x end end class Bar end foo = Foo.new(1) bar = Bar.new tuple = {foo, bar} tuple_class = tuple.class foo_class = tuple_class[0] foo2 = foo_class.new(2) foo2.x CRYSTAL end it "gets size at compile time" do run(<<-CRYSTAL).to_i.should eq(2) struct Tuple def my_size {{ T.size }} end end {1, 1}.my_size CRYSTAL end it "allows tuple covariance" do run(<<-CRYSTAL).to_i.should eq(42) class Obj def initialize @tuple = {Foo.new} end def tuple=(@tuple) end def tuple @tuple end end class Foo def bar 21 end end class Bar < Foo def bar 42 end end obj = Obj.new obj.tuple = {Bar.new} obj.tuple[0].bar CRYSTAL end it "merges two tuple types of same size (1)" do run(<<-CRYSTAL).to_i.should eq(20) def foo if 1 == 2 {"foo", 10} else {"foo", nil} end end val = foo[1] val || 20 CRYSTAL end it "merges two tuple types of same size (2)" do run(<<-CRYSTAL).to_i.should eq(10) def foo if 1 == 1 {"foo", 10} else {"foo", nil} end end val = foo[1] val || 20 CRYSTAL end it "assigns tuple to compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) ptr = Pointer({Int32 | String, Bool | Char}).malloc(1_u64) # Here the compiler should cast each value ptr.value = {42, 'x'} val = ptr.value[0] val.as?(Int32) || 10 CRYSTAL end it "upcasts tuple inside compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) def foo if 1 == 2 {"hello", false} else {42, 'x'} end end val = foo[0] val.as?(Int32) || 10 CRYSTAL end it "assigns tuple union to compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) tup1 = {"hello", false} tup2 = {3} tup3 = {42, 'x'} ptr = Pointer(typeof(tup1, tup2, tup3)).malloc(1_u64) ptr.value = tup3 val = ptr.value[0] val.as?(Int32) || 10 CRYSTAL end it "upcasts tuple union to compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) def foo if 1 == 2 {"hello", false} || {3} else {42, 'x'} end end val = foo[0] val.as?(Int32) || 10 CRYSTAL end it "assigns tuple inside union to union with compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) tup1 = {"hello", false} tup2 = {3} union1 = tup1 || tup2 tup3 = {42, 'x'} tup4 = {4} union2 = tup3 || tup4 ptr = Pointer(typeof(union1, union2)).malloc(1_u64) ptr.value = union2 val = ptr.value[0] val.as?(Int32) || 10 CRYSTAL end it "upcasts tuple inside union to union with compatible tuple" do run(<<-CRYSTAL).to_i.should eq(42) def foo if 1 == 2 tup1 = {"hello", false} tup2 = {3} union1 = tup1 || tup2 union1 else tup3 = {42, 'x'} tup4 = {4} union2 = tup3 || tup4 union2 end end val = foo[0] val.as?(Int32) || 10 CRYSTAL end it "codegens union of tuple of float with tuple of tuple of float" do run(<<-CRYSTAL).to_i.should eq(42) a = {1.5} b = { {22.0, 20.0} } c = b || a v = c[0] if v.is_a?(Float64) 10 else v[0].to_i! &+ v[1].to_i! end CRYSTAL end it "provides T as a tuple literal" do run(<<-CRYSTAL).to_string.should eq("TupleLiteral") struct Tuple def self.foo {{ T.class_name }} end end Tuple(Nil, Int32).foo CRYSTAL end it "passes empty tuple and empty named tuple to a method (#2852)" do codegen(<<-CRYSTAL) def foo(*binds) baz(binds) end def bar(**binds) baz(binds) end def baz(binds) binds end foo bar CRYSTAL end it "assigns two same-size tuple types to a same var (#3132)" do run(<<-CRYSTAL).to_i.should eq(2) t = {true} t t = {2} t[0] CRYSTAL end it "downcasts union to mixed tuple type" do run(<<-CRYSTAL).to_i.should eq(1) t = {1} || 2 || {true} t = {1} t[0] CRYSTAL end it "downcasts union to mixed union with mixed tuple types" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" t = {1} || 2 || {true} t = {1} || 2 t.as(Tuple)[0] CRYSTAL end it "downcasts union inside tuple to value (#3907)" do codegen(<<-CRYSTAL) struct Foo end foo = Foo.new x = {0, foo} z = x[0] x = {0, z} CRYSTAL end end private def range_new %( struct Range(B, E) def initialize(@begin : B, @end : E, @exclusive : Bool = false) end end ) end ================================================ FILE: spec/compiler/codegen/type_declaration_spec.cr ================================================ require "../../spec_helper" describe "Code gen: type declaration" do it "codegens initialize instance var" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x = 1 def x @x end end Foo.new.x CRYSTAL end it "codegens initialize instance var of superclass" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x = 1 def x @x end end class Bar < Foo end Bar.new.x CRYSTAL end it "codegens initialize instance var with var declaration" do run(<<-CRYSTAL).to_i.should eq(1) class Foo @x : Int32 = begin a = 1 a end def x @x end end Foo.new.x CRYSTAL end it "declares and initializes" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @x : Int32 = 42 def x @x end end Foo.new.x CRYSTAL end it "declares and initializes var" do run(<<-CRYSTAL).to_i.should eq(42) a : Int32 = 42 a CRYSTAL end end ================================================ FILE: spec/compiler/codegen/uninitialized_spec.cr ================================================ require "../../spec_helper" describe "Code gen: uninitialized" do it "codegens declare var and read it" do run("a = uninitialized Int32; a") end it "codegens declare var and changes it" do run("a = uninitialized Int32; while a != 10; a = 10; end; a").to_i.should eq(10) end it "codegens declare instance var" do run(<<-CRYSTAL).to_i.should eq(0) class Foo def initialize @x = uninitialized Int32 end def x @x end end Foo.new.x CRYSTAL end it "codegens declare instance var with static array type" do run(<<-CRYSTAL) class Foo def initialize @x = uninitialized Int32[4] end def x @x end end Foo.new.x nil CRYSTAL end it "doesn't break on inherited declared var (#390)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo def initialize @x = 1 end end class Bar < Foo def initialize @x = uninitialized Int32 @x = 1 @y = 2 end def x @x end def y @y end end bar = Bar.new bar.x &+ bar.y CRYSTAL end it "works inside while/begin/rescue (bug inside #759)" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" a = 3 while 1 begin buf = uninitialized Int32 buf + 1 break if a == 3 rescue end end a CRYSTAL end it "works with uninitialized NoReturn (#3314)" do codegen(<<-CRYSTAL, inject_primitives: false) def foo x = uninitialized NoReturn if 1 x = yield end x end def bar foo { return } end bar CRYSTAL end it "codegens value (#3641)" do run(<<-CRYSTAL).to_b.should be_true x = y = uninitialized Int32 x == y CRYSTAL end end ================================================ FILE: spec/compiler/codegen/union_type_spec.cr ================================================ require "../../spec_helper" describe "Code gen: union type" do it "codegens union type when obj is union and no args" do run("a = 1; a = 2.5_f32; a.to_f").to_f64.should eq(2.5) end it "codegens union type when obj is union and arg is union" do run("a = 1; a = 1.5_f32; (a + a).to_f").to_f64.should eq(3) end it "codegens union type when obj is not union but arg is" do run("a = 1; b = 2; b = 1.5_f32; (a + b).to_f").to_f64.should eq(2.5) end it "codegens union type when obj union but arg is not" do run("a = 1; b = 2; b = 1.5_f32; (b + a).to_f").to_f64.should eq(2.5) end it "codegens union type when no obj" do run("def foo(x); x; end; a = 1; a = 2.5_f32; foo(a).to_f").to_f64.should eq(2.5) end it "codegens union type when no obj and restrictions" do run("def foo(x : Int); 1.5; end; def foo(x : Float); 2.5; end; a = 1; a = 3.5_f32; foo(a).to_f").to_f64.should eq(2.5) end it "codegens union type as return value" do run("def foo; a = 1; a = 2.5_f32; a; end; foo.to_f").to_f64.should eq(2.5) end it "codegens union type for instance var" do run(<<-CRYSTAL).to_f64.should eq(3) struct Float def &+(other) self + other end end struct Int32 def &+(other : Float) self + other end end class Foo @value : Int32 | Float32 def initialize(value) @value = value end def value=(@value); end def value; @value; end end f = Foo.new(1) f.value = 1.5_f32 (f.value &+ f.value).to_f CRYSTAL end it "codegens if with same nested union" do run(<<-CRYSTAL).to_i.should eq(1) if true if true 1 else 2.5_f32 end else if true 1 else 2.5_f32 end end.to_i! CRYSTAL end it "assigns union to union" do run(<<-CRYSTAL).to_i.should eq(97) require "prelude" struct Nil; def to_i; 0; end; end struct Char def to_i ord end end class Foo @x : Int32 | Char | Nil def foo(x) @x = x @x = @x || 1 end def x @x end end f = Foo.new f.foo 1 f.foo 'a' f.x.to_i CRYSTAL end it "assigns union to larger union" do run(<<-CRYSTAL).to_string.should eq("d") require "prelude" a = 1 a = 1.1_f32 b = "c" b = 'd' a = b a.to_s CRYSTAL end it "assigns union to larger union when source is nilable 1" do value = run(<<-CRYSTAL).to_string require "prelude" a = 1 b = nil b = Reference.new a = b a.to_s CRYSTAL value.should contain("Reference") end it "assigns union to larger union when source is nilable 2" do run(<<-CRYSTAL).to_string.should eq("") require "prelude" a = 1 b = Reference.new b = nil a = b a.to_s CRYSTAL end it "dispatch call to object method on nilable" do run(<<-CRYSTAL) require "prelude" class Foo end a = nil a = Foo.new a.nil? CRYSTAL end it "sorts restrictions when there are unions" do run(<<-CRYSTAL).to_i.should eq(2) class Middle end class Top < Middle end class Another1 end class Another2 end def type_id(type : Another2) 1 end def type_id(y : Top) 2 end def type_id(y : Middle | Another1) 3 end def type_id(y) 4 end t = Top.new || Another1.new type_id t CRYSTAL end it "codegens union to_s" do str = run(<<-CRYSTAL).to_string require "prelude" def foo(x : T) forall T T.to_s end a = 1 || 1.5 foo(a) CRYSTAL str.in?("(Int32 | Float64)", "(Float64 | Int32)").should be_true end it "provides T as a tuple literal" do run(<<-CRYSTAL).to_string.should eq("TupleLiteral") struct Union def self.foo {{ T.class_name }} end end Union(Nil, Int32).foo CRYSTAL end it "respects union payload alignment when upcasting Bool (#14898)" do mod = codegen(<<-CRYSTAL) x = uninitialized Bool | UInt8[64] x = true CRYSTAL str = mod.to_s {% if LibLLVM::IS_LT_150 %} str.should match(/store i512 1, i512\* %\d+, align 8/) {% else %} str.should match(/store i512 1, ptr %\d+, align 8/) {% end %} # an i512 store defaults to 16-byte alignment, which is undefined behavior # as it overestimates the actual alignment of `x`'s data field (x86 in # particular segfaults on misaligned 16-byte stores) str.should_not contain("align 16") end end ================================================ FILE: spec/compiler/codegen/until_spec.cr ================================================ require "../../spec_helper" describe "Codegen: until" do it "codegens until" do run(<<-CRYSTAL).to_i.should eq(10) a = 1 until a == 10 a = a &+ 1 end a CRYSTAL end end ================================================ FILE: spec/compiler/codegen/var_spec.cr ================================================ require "../../spec_helper" describe "Code gen: var" do it "codegens var" do run("a = 1; 1.5; a").to_i.should eq(1) end it "codegens var with type declaration" do run("a = (b : Int32 = 1); a").to_i.should eq(1) end it "codegens ivar assignment when not-nil type filter applies" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo if @a x = @a end @a = 2 end end foo = Foo.new foo.foo CRYSTAL end it "codegens bug with instance vars and ssa" do run(<<-CRYSTAL).to_i.should eq(-1) class Foo def initialize @angle = 0 end def foo if 1 == 2 @angle &+= 1 else @angle &-= 1 end end end f = Foo.new f.foo CRYSTAL end it "codegens bug with var, while, if, break and ssa" do run(<<-CRYSTAL).to_i.should eq(2) a = 1 a = 2 while 1 == 1 if 1 == 2 a = 3 else break end end a CRYSTAL end it "codegens bug with union of int, nil and string (1): assigning nil to union must fill all zeros" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def foo 1 end end class String def foo 2 end end x = 80 if true x = nil else x = "a" end x.foo CRYSTAL end it "codegens bug with union of int, nil and string (2): assigning nil to union must fill all zeros" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def foo 1 end end class String def foo 2 end end x = 443 if true x = nil else x = "a" end x.foo CRYSTAL end it "codegens assignment that can never be reached" do codegen(<<-CRYSTAL) if 1 == 1 && (x = nil) z = x end CRYSTAL end it "works with typeof with assignment (#828)" do run(<<-CRYSTAL).to_i.should eq(123) class String; def to_i!; 0; end; end a = 123 typeof(a = "hello") a.to_i! CRYSTAL end it "assigns to underscore" do run(<<-CRYSTAL).to_i.should eq(2) _ = (b = 2) b CRYSTAL end end ================================================ FILE: spec/compiler/codegen/virtual_spec.cr ================================================ require "../../spec_helper" describe "Code gen: virtual type" do it "call base method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco 1 end end class Bar < Foo end a = Foo.new a = Bar.new a.coco CRYSTAL end it "call overwritten method" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def coco 1 end end class Bar < Foo def coco 2 end end a = Foo.new a = Bar.new a.coco CRYSTAL end it "call base overwritten method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco 1 end end class Bar < Foo def coco 2 end end a = Bar.new a = Foo.new a.coco CRYSTAL end it "dispatch call with virtual type argument" do run(<<-CRYSTAL).to_i.should eq(2) class Foo end class Bar < Foo end def coco(x : Bar) 1 end def coco(x) 2 end a = Bar.new a = Foo.new coco(a) CRYSTAL end it "can belong to union" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo; 1; end end class Bar < Foo; end class Baz def foo; 2; end end x = Foo.new x = Bar.new x = Baz.new x.foo CRYSTAL end it "lookup instance variables in parent types" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @x = 1 end def foo @x end end class Bar < Foo def foo @x &+ 1 end end a = Bar.new || Foo.new a.foo CRYSTAL end it "assign instance variable in virtual type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo @x = 1 end end class Bar < Foo end f = Foo.new || Bar.new f.foo CRYSTAL end it "codegens non-virtual call that calls virtual call to another virtual call" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo foo2 end def foo2 1 end end class Bar < Foo def bar foo end end bar = Bar.new bar.bar CRYSTAL end it "casts virtual type to base virtual type" do run(<<-CRYSTAL).to_i.should eq(1) class Object def bar 1 end end class Foo def foo bar end end class Bar < Foo end f = Foo.new || Bar.new f.foo CRYSTAL end it "codegens call to Object#to_s from virtual type" do run(<<-CRYSTAL) require "prelude" class Foo end class Bar < Foo end a = Foo.new || Bar.new a.to_s CRYSTAL end it "codegens call to Object#to_s from nilable type" do run(<<-CRYSTAL) require "prelude" class Foo end a = nil || Foo.new a.to_s CRYSTAL end it "codegens virtual call with explicit self" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo self.bar end def bar 1 end end class Bar < Foo end f = Foo.new || Bar.new f.foo CRYSTAL end it "codegens virtual call with explicit self and nilable type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo self.bar end def bar 1 end end class Bar < Foo end struct Nil def foo 2 end end f = Bar.new || nil f.foo.to_i! CRYSTAL end it "initializes ivars to nil even if object never instantiated" do run(<<-CRYSTAL) require "prelude" class Ref end class Foo def foo bar self end end class Bar < Foo end class Baz < Foo def initialize @x = Ref.new end def x @x end end def bar(x) end def bar(x : Baz) x.x.to_s end f = Foo.new || Bar.new f.foo CRYSTAL end it "doesn't lookup in Value+ when virtual type is Object+" do run(<<-CRYSTAL).to_b.should be_true class Object def foo !nil? end end class Foo end a = Foo.new a.foo CRYSTAL end it "correctly dispatch call with block when the obj is a virtual type" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def each yield self end def foo 1 end end class Bar < Foo def foo 2 end end a = Foo.new a = Bar.new y = 0 a.each {|x| y = x.foo} y CRYSTAL end it "dispatch call with nilable virtual arg" do run(<<-CRYSTAL).to_i.should eq(1) class Foo end class Bar < Foo end def foo(x) 1 end def foo(x : Bar) 2 end def lala 1 == 2 ? nil : Foo.new || Bar.new end x = lala foo(x) CRYSTAL end it "calls class method 1" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.foo 1 end end class Bar < Foo def self.foo 2 end end (Foo.new || Bar.new).class.foo CRYSTAL end it "calls class method 2" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end class Bar < Foo def self.foo 2 end end (Bar.new || Foo.new).class.foo CRYSTAL end it "calls class method 3" do run(<<-CRYSTAL).to_i.should eq(1) class Base def self.foo 1 end end class Foo < Base end class Bar < Foo def self.foo 2 end end (Foo.new || Base.new).class.foo CRYSTAL end it "dispatches on virtual metaclass (1)" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.coco 1 end end class Bar < Foo def self.coco 2 end end some_long_var = Foo || Bar some_long_var.coco CRYSTAL end it "dispatches on virtual metaclass (2)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.coco 1 end end class Bar < Foo def self.coco 2 end end some_long_var = Bar || Foo some_long_var.coco CRYSTAL end it "dispatches on virtual metaclass (3)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.coco 1 end end class Bar < Foo def self.coco 2 end end class Baz < Bar end some_long_var = Baz || Foo some_long_var.coco CRYSTAL end it "codegens new for simple type, then for virtual" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end def x @x end end class Bar < Foo end x = Foo.new(1) y = (Foo || Bar).new(1) y.x CRYSTAL end it "codegens new twice for virtual" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@x : Int32) end def x @x end end class Bar < Foo end y = (Foo || Bar).new(1) y = (Foo || Bar).new(1) y.x CRYSTAL end it "codegens allocate for virtual type with custom new" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.new allocate end def foo 1 end end class Bar < Foo def foo 2 end end foo = (Bar || Foo).new foo.foo CRYSTAL end it "returns type with virtual type def type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def foo 1 end end class Bar < Foo def foo 2 end end def foo return Foo.new if 1 == 1 Bar.new end foo.foo CRYSTAL end it "casts virtual type to union" do run(<<-CRYSTAL).to_i.should eq(3) class Foo end class Bar < Foo def foo 2 end end class Baz < Foo def foo 3 end end def x(f : Bar | Baz) f.foo end def x(f) 0 end f = Baz.new || Bar.new x(f) CRYSTAL end it "casts union to virtual" do run(<<-CRYSTAL).to_b.should be_true module Moo end abstract class Foo end class Bar < Foo include Moo end class Baz < Foo include Moo end def foo(x : Moo) p = Pointer(Foo).malloc(1_u64) p.value = x p.value.object_id end def foo(x) 0_u64 end reference = Bar.new || Baz.new reference.object_id == foo(reference) CRYSTAL end it "codegens virtual method of abstract metaclass" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.foo 1 end end abstract class Bar < Foo def self.foo 2 end end class Baz < Foo def self.foo 3 end end (Bar || Foo || Baz).foo CRYSTAL end it "codegens new for virtual class with one type" do run(<<-CRYSTAL).to_i.should eq(123) require "prelude" abstract class Foo end class Bar < Foo def foo 123 end end p = Pointer(Foo.class).malloc(1_u64) p.value = Bar p.value.new.foo CRYSTAL end it "codegens new for virtual class with two types" do run(<<-CRYSTAL).to_i.should eq(456) require "prelude" abstract class Foo end class Bar < Foo def foo 123 end end class Baz < Foo def foo 456 end end p = Pointer(Foo.class).malloc(1_u64) p.value = Bar p.value = Baz p.value.new.foo CRYSTAL end it "codegens new for new on virtual abstract class (#3835)" do run(<<-CRYSTAL).to_string.should eq("Can't instantiate abstract class Foo") require "prelude" abstract class Foo end class Bar < Foo def foo 123 end end begin (Foo || Bar).new "" rescue ex ex.message.not_nil! end CRYSTAL end it "casts metaclass union type to virtual metaclass type (#6298)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def self.x 1 end end class Bar < Foo def self.x 2 end end class Baz < Foo def self.x 3 end end class Moo def initialize(@foo : Foo.class) end def foo @foo end end klass = Bar || Baz Moo.new(klass).foo.x CRYSTAL end end ================================================ FILE: spec/compiler/codegen/void_spec.cr ================================================ require "../../spec_helper" describe "Code gen: void" do it "codegens void assignment" do run(<<-CRYSTAL).to_i.should eq(1) fun foo : Void end a = foo a 1 CRYSTAL end it "codegens void assignment in case" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" fun foo : Void end def bar case 1 when 1 foo when 2 raise "oh no" else end end bar 1 CRYSTAL end it "codegens void assignment in case with local variable" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" fun foo : Void end def bar case 1 when 1 a = 1 foo when 2 raise "oh no" else end end bar 1 CRYSTAL end it "codegens unreachable code" do run(<<-CRYSTAL) a = nil if a b = a.foo end CRYSTAL end it "codegens no return assignment" do codegen(<<-CRYSTAL) lib LibC fun exit : NoReturn end a = LibC.exit a CRYSTAL end it "allows passing void as argument to method" do codegen(<<-CRYSTAL) lib LibC fun foo end def bar(x) end def baz LibC.foo end bar(baz) CRYSTAL end it "returns void from nil functions, doesn't crash when passing value" do run(<<-CRYSTAL).to_i.should eq(1) def baz(x) 1 end struct Nil def bar baz(self) end end def foo 1 nil end foo.bar CRYSTAL end end ================================================ FILE: spec/compiler/codegen/while_spec.cr ================================================ require "../../spec_helper" describe "Codegen: while" do it "codegens def with while" do run("def foo; while false; 1; end; end; foo") end it "codegens while with false" do run("a = 1; while false; a = 2; end; a").to_i.should eq(1) end it "codegens while with non-false condition" do run("a = 1; while a < 10; a = a &+ 1; end; a").to_i.should eq(10) end it "break without value" do run("a = 0; while a < 10; a &+= 1; break; end; a").to_i.should eq(1) end it "conditional break without value" do run("a = 0; while a < 10; a &+= 1; break if a > 5; end; a").to_i.should eq(6) end it "break with value" do run(<<-CRYSTAL).to_i.should eq(4) struct Nil; def to_i!; 0; end; end a = 0 b = while a < 10 a &+= 1 break a &+ 3 end b.to_i! CRYSTAL end it "conditional break with value" do run(<<-CRYSTAL).to_i.should eq(9) struct Nil; def to_i!; 0; end; end a = 0 b = while a < 10 a &+= 1 break a &+ 3 if a > 5 end b.to_i! CRYSTAL end it "break with value, condition fails" do run(<<-CRYSTAL).to_b.should be_true a = while 1 == 2 break 1 end a.nil? CRYSTAL end it "endless break with value" do run(<<-CRYSTAL).to_i.should eq(4) a = 0 while true a &+= 1 break a &+ 3 end CRYSTAL end it "endless conditional break with value" do run(<<-CRYSTAL).to_i.should eq(9) a = 0 while true a &+= 1 break a &+ 3 if a > 5 end CRYSTAL end it "codegens endless while" do codegen "while true; end" end it "codegens while with declared var 1" do run(<<-CRYSTAL).to_i.should eq(0) struct Nil; def to_i!; 0; end; end while 1 == 2 a = 2 end a.to_i! CRYSTAL end it "codegens while with declared var 2" do run(<<-CRYSTAL).to_i.should eq(3) struct Nil; def to_i!; 0; end; end while 1 == 1 a = 2 if 1 == 1 a = 3 break end end a.to_i! CRYSTAL end it "codegens while with declared var 3" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil; def to_i!; 0; end; end while 1 == 1 a = 1 if a break else 2 end end a.to_i! CRYSTAL end it "skip block with next" do run(<<-CRYSTAL).to_i.should eq(25) i = 0 x = 0 while i < 10 i &+= 1 next if i.unsafe_mod(2) == 0 x &+= i end x CRYSTAL end it "doesn't crash on a = NoReturn" do codegen(<<-CRYSTAL) lib LibFoo fun foo : NoReturn end while a = LibFoo.foo a end CRYSTAL end it "doesn't crash on #2767" do run(<<-CRYSTAL).to_i.should eq(10) lib LibC fun exit(Int32) : NoReturn end x = 'x' while 1 == 2 if true x = (LibC.exit(0); 1) end end x 10 CRYSTAL end it "doesn't crash on #2767 (2)" do run(<<-CRYSTAL).to_i.should eq(10) lib LibC fun exit(Int32) : NoReturn end x = 'x' while 1 == 2 x = LibC.exit(0).as(Int32) end x 10 CRYSTAL end it "doesn't crash on #2767 (3)" do run(<<-CRYSTAL).to_i.should eq(10) lib LibC fun exit(Int32) : NoReturn end x = 'x' while 1 == 2 if true x = if true LibC.exit(0) else 3 end end end x 10 CRYSTAL end it "doesn't crash on #2767 (4)" do run(<<-CRYSTAL).to_i.should eq(10) lib LibC fun exit(Int32) : NoReturn end x = 'x' while 1 == 2 if true x = (LibC.exit(0); 1) end y = x z = y x = z end x 10 CRYSTAL end it "doesn't crash on while true begin break rescue (#7786)" do codegen(<<-CRYSTAL) require "prelude" while true begin foo = 1 break rescue end end foo CRYSTAL end end ================================================ FILE: spec/compiler/codegen/yield_with_scope_spec.cr ================================================ require "../../spec_helper" describe "Semantic: yield with scope" do it "uses scope in global method" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" def foo; with 1 yield; end foo do succ end CRYSTAL end it "uses scope in instance method" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" def foo; with 1 yield; end class Foo def test foo do succ end end def succ 10 end end Foo.new.test CRYSTAL end it "it uses self for instance method" do run(<<-CRYSTAL).to_i.should eq(10) require "prelude" def foo; with 1 yield; end class Foo def test foo do self.succ end end def succ 10 end end Foo.new.test CRYSTAL end it "it invokes global method inside block of yield scope" do run(<<-CRYSTAL).to_i.should eq(3) require "prelude" def foo with -1 yield end def plus_two(x) x + 2 end foo do plus_two abs end CRYSTAL end it "generate right code when yielding struct as scope" do run(<<-CRYSTAL).to_i.should eq(1) struct Foo def bar; end end def foo with Foo.new yield 1 end foo { bar } CRYSTAL end it "doesn't explode if specifying &block but never using it (#181)" do codegen(<<-CRYSTAL) class Foo def a(&block) with self yield end def aa end end a = Foo.new a.a { aa } a.a { aa } CRYSTAL end it "uses instance variable of enclosing scope" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo with self yield end end class Bar def initialize @x = 1 end def bar Foo.new.foo do @x &+ 1 end end end Bar.new.bar CRYSTAL end it "uses method of enclosing scope" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo with self yield end end class Bar def bar Foo.new.foo do baz &+ 1 end end def baz 1 end end Bar.new.bar CRYSTAL end it "uses method of with object" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def initialize @x = 1 end def foo with self yield end def coco @x &+ 1 end end class Bar def bar Foo.new.foo do coco end end end Bar.new.bar CRYSTAL end it "yields with dispatch (#2171) (1)" do run(<<-CRYSTAL).to_i.should eq(10) class Foo def method(x : Int32) 10 end def method(x : Float64) 20 end end def foo with Foo.new yield end foo do method(1 || 1.5) end CRYSTAL end it "yields virtual type (#2171) (2)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def method 1 end end class Bar < Foo def method 2 end end def foo with (Bar.new || Foo.new) yield end foo { method } CRYSTAL end end ================================================ FILE: spec/compiler/compiler_spec.cr ================================================ require "../spec_helper" require "./spec_helper" describe "Compiler" do it "has a valid version" do SemanticVersion.parse(Crystal::Config.version) end it "compiles a file" do with_temp_executable "compiler_spec_output" do |path| Crystal::Command.run ["build"].concat(program_flags_options).concat([compiler_datapath("compiler_sample"), "-o", path]) File.exists?(path).should be_true `#{Process.quote(path)}`.should eq("Hello!") end end it "runs subcommand in preference to a filename " do Dir.cd compiler_datapath do with_temp_executable "compiler_spec_output" do |path| Crystal::Command.run ["build"].concat(program_flags_options).concat(["compiler_sample", "-o", path]) File.exists?(path).should be_true `#{Process.quote(path)}`.should eq("Hello!") end end end it "treats all arguments post-filename as program arguments" do with_tempfile "args_test" do |path| Process.run(ENV["CRYSTAL_SPEC_COMPILER_BIN"]? || "bin/crystal", [File.join(compiler_datapath, "args_test"), "-Dother_flag", "--", "bar", path]) File.read(path).should eq(<<-FILE) ["-Dother_flag", "--", "bar"] {other_flag: false} FILE end end end ================================================ FILE: spec/compiler/config_spec.cr ================================================ require "../spec_helper" require "./spec_helper" describe Crystal::Config do it ".host_target" do {% begin %} {% host_triple = Crystal.constant("HOST_TRIPLE") || Crystal::DESCRIPTION.lines[-1].gsub(/^Default target: /, "") %} Crystal::Config.host_target.should eq Crystal::Codegen::Target.new({{ host_triple }}) {% end %} end {% if flag?(:linux) %} it ".linux_runtime_libc" do Crystal::Config.linux_runtime_libc.should eq {{ flag?(:musl) ? "musl" : "gnu" }} end {% end %} end ================================================ FILE: spec/compiler/crystal/commands/clear_cache_spec.cr ================================================ require "../../../spec_helper" class Crystal::CacheDir class_setter instance def initialize(@dir) Dir.mkdir_p(dir) end end describe Crystal::Command do describe "clear_cache" do around_each do |example| old_cache_dir = CacheDir.instance temp_dir_name = File.tempname begin CacheDir.instance = CacheDir.new(temp_dir_name) example.run ensure FileUtils.rm_rf(temp_dir_name) CacheDir.instance = old_cache_dir end end it "clears any cached compiler files" do file_path = File.tempname(dir: CacheDir.instance.dir) Dir.mkdir_p(File.dirname(file_path)) File.touch(file_path) File.exists?(file_path).should be_true Crystal::Command.run(["clear_cache"]) File.exists?(file_path).should be_false File.exists?(CacheDir.instance.dir).should be_false end end end ================================================ FILE: spec/compiler/crystal/tools/context_spec.cr ================================================ require "../../../spec_helper" private def processed_context_visitor(code, cursor_location) compiler = Compiler.new compiler.no_codegen = true compiler.prelude = "empty" result = compiler.compile(Compiler::Source.new(".", code), "fake-no-build") visitor = ContextVisitor.new(cursor_location) process_result = visitor.process(result) {visitor, process_result} end private def run_context_tool(code, &) cursor_location = nil code.lines.each_with_index do |line, line_number_0| if column_number = line.index('‸') cursor_location = Location.new(".", line_number_0 + 1, column_number + 1) end end code = code.delete('‸') if cursor_location _, result = processed_context_visitor(code, cursor_location) yield result else raise "no cursor found in spec" end end private def assert_context_keys(code, *variables) run_context_tool(code) do |result| result.contexts.should_not be_nil result.contexts.not_nil!.each do |context| context.keys.should eq(variables.to_a) end end end private def assert_context_includes(code, variable, var_types) run_context_tool(code) do |result| result.contexts.should_not be_nil result.contexts.not_nil!.map(&.[variable].to_s).should eq(var_types) end end # References # # ‸ marks location of the cursor to use # describe "context" do it "includes args" do assert_context_includes %( def foo(a) ‸ 1 end foo(1i64) ), "a", ["Int64"] end it "consider different instances of def" do assert_context_includes %( def foo(a) ‸ 1 end foo(1i64) foo("foo") ), "a", ["Int64", "String"] end it "includes assignments" do assert_context_includes %( def foo(a) b = a ‸ 1 end foo(1i64) foo("foo") ), "b", ["Int64", "String"] end it "includes block args" do assert_context_includes %( def bar(x) yield x end def foo(a) bar a do |b| ‸ 1 end 1 end foo(1i64) foo("foo") ), "b", ["Int64", "String"] end it "includes top level vars" do assert_context_includes %( a = 0i64 ‸ 1 ), "a", ["Int64"] end it "includes last call" do assert_context_includes %( class Foo def lorem @lorem end def initialize(@lorem : Int64) end end def foo(f) end f = Foo.new(1i64) foo f.lo‸rem 1 ), "f.lorem", ["Int64"] end it "does not includes temp variables" do assert_context_keys %( a = 0i64 ‸ 1 ), "a" end it "does includes regex special variables" do assert_context_keys %( def match $~ = "match" end def foo s = "foo" match ‸ 0 end foo ), "s", "$~" end it "does includes self on classes" do assert_context_includes %( class Foo def foo ‸ 0 end end f = Foo.new f.foo 0 ), "self", ["Foo"] end it "does includes args, instance vars, local variables and expressions on instance methods" do assert_context_keys %( class Foo def foo(the_arg) @ivar = 2 the_arg.fo‸o(self) 0 end end f = Foo.new f.foo(Foo.new) 0 ), "self", "@ivar", "the_arg", "the_arg.foo(self)" end it "can handle union types" do assert_context_includes %( a = 1_i64.as(Int64 | String) ‸ 0 ), "a", ["(Int64 | String)"] end it "can display text output" do run_context_tool(%( a = 1_i64.as(Int64 | String) ‸ 0 )) do |result| String::Builder.build do |io| result.to_text(io) end.should eq %(1 possible context found | Expr | Type | ------------------------- | a | Int64 | String | ) end end it "can display json output" do run_context_tool(%( a = 1_i64.as(Int64 | String) ‸ 0 )) do |result| String::Builder.build do |io| result.to_json(io) end.should eq %({"status":"ok","message":"1 possible context found","contexts":[{"a":"Int64 | String"}]}) end end it "can get context of empty def" do assert_context_includes %( def foo(a) ‸ end foo(0i64) ), "a", ["Int64"] end it "can get context of empty yielded block" do assert_context_includes %( def it_like yield end it_like do a = 1i64‸ end ), "a", ["Int64"] end it "can get context of yielded block" do assert_context_keys %( def foo(a) b = a + 1 ‸ yield b end foo 1 do |x| end ), "a", "b" end it "can get context of nested yielded block" do assert_context_keys %( def foo(a) b = a + 1 ‸ yield b end def bar foo 1 do |x| yield x end end bar do |y| end ), "a", "b" end it "can get context inside a module" do assert_context_includes %( module Foo class Bar def bar(o) ‸ end end end Foo::Bar.new.bar("foo") ), "o", ["String"] end it "can get context inside class methods" do assert_context_includes %( class Bar def self.bar(o) ‸ end end Bar.bar("foo") ), "o", ["String"] end it "can get context inside initialize" do assert_context_keys %( class Bar def initialize(@ivar : String) ‸ end end Bar.new("s") ), "self", "@ivar", "ivar" end it "can get context in generic class" do assert_context_keys %( class Foo(T, S) def foo(a) ‸ end end Foo(String, Char).new.foo(1) ), "T", "S", "self", "a" assert_context_includes %( class Foo(T, S) def foo(a) ‸ end end Foo(String, Char).new.foo(1) ), "T", ["String"] end it "can get context in contained class' class method" do assert_context_keys %( module Baz class Bar(T) class Foo def self.bar_foo(a) ‸ end end end end Baz::Bar::Foo.bar_foo(1) ), "self", "a" end it "use type filters from is_a?" do assert_context_includes %( def foo(c) if c.is_a?(String) ‸ end end foo(1 < 0 ? nil : "s") ), "c", ["String"] end it "use type filters from if var" do assert_context_includes %( def foo(c) if c ‸ end end foo(1 < 0 ? nil : "s") ), "c", ["String"] end it "can get context in file private method" do assert_context_keys %( private def foo(a) ‸ end foo 100 ), "a" end it "can get context in file private module" do assert_context_keys %( private module Foo def self.foo(a) ‸ end end Foo.foo 100 ), "self", "a" end it "can't get context from uncalled method" do run_context_tool %( def foo(value) ‸ end ) do |result| result.status.should eq("failed") result.message.should match(/never called/) end end end ================================================ FILE: spec/compiler/crystal/tools/doc/directives_spec.cr ================================================ require "../../../spec_helper" describe Crystal::Doc::Generator do context ":nodoc:" do it "hides documentation from being generated for methods" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program class Foo # :nodoc: # # Some docs def foo end end CRYSTAL generator = Doc::Generator.new program, [""] generator.type(program.types["Foo"]).lookup_method("foo").should be_nil end it "hides documentation from being generated for classes" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :nodoc: class Foo end CRYSTAL generator = Doc::Generator.new program, [""] generator.must_include?(program.types["Foo"]).should be_false end end context ":showdoc:" do it "shows documentation for private methods" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program class Foo # :showdoc: # # Some docs private def foo end end CRYSTAL generator = Doc::Generator.new program, [""] a_def = generator.type(program.types["Foo"]).lookup_method("foo").not_nil! a_def.doc.should eq("Some docs") a_def.visibility.should eq("private") end it "shows documentation for private macros" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program class Foo # :showdoc: # # Some docs private macro foo end end CRYSTAL generator = Doc::Generator.new program, [""] a_macro = generator.type(program.types["Foo"]).lookup_macro("foo").not_nil! a_macro.doc.should eq("Some docs") a_macro.visibility.should eq("private") end it "shows documentation for nested objects if a lib is marked with :showdoc:" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :showdoc: lib Foo # docs for `foo` fun foo end CRYSTAL generator = Doc::Generator.new program, [""] generator.must_include?(program.types["Foo"]).should be_true generator.type(program.types["Foo"]).lookup_method("foo").should_not be_nil end it "does not include documentation for methods within a :nodoc: namespace" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :nodoc: class Foo # :showdoc: # # Some docs private def foo end end CRYSTAL generator = Doc::Generator.new program, [""] # If namespace isn't included, don't need to check if the method is included generator.must_include?(program.types["Foo"]).should be_false end it "does not include documentation for private and protected methods and objects in a :showdoc: namespace" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :showdoc: class Foo # Some docs for `foo` private def foo end # Some docs for `bar` protected def bar end # Some docs for `Baz` private class Baz end end CRYSTAL generator = Doc::Generator.new program, [""] generator.type(program.types["Foo"]).lookup_method("foo").should be_nil generator.type(program.types["Foo"]).lookup_method("bar").should be_nil generator.must_include?(generator.type(program.types["Foo"]).lookup_path("Baz")).should be_false end it "does not include documentation for a :showdoc: fun inside a lib not marked with :showdoc:" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program lib Foo # :showdoc: fun foo end CRYSTAL generator = Doc::Generator.new program, [""] generator.must_include?(program.types["Foo"]).should be_false end it "doesn't show a method marked :nodoc: within a :showdoc: namespace" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :showdoc: class Foo # :nodoc: # Some docs for `foo` def foo end end CRYSTAL generator = Doc::Generator.new program, [""] generator.type(program.types["Foo"]).lookup_method("foo").should be_nil end it "doesn't show a fun marked :nodoc: within a :showdoc: lib" do program = top_level_semantic(<<-CRYSTAL, wants_doc: true).program # :showdoc: lib Foo # :nodoc: # Some docs for `foo` fun foo fun bar end CRYSTAL generator = Doc::Generator.new program, [""] generator.type(program.types["Foo"]).lookup_method("foo").should be_nil generator.type(program.types["Foo"]).lookup_method("bar").should_not be_nil end end end ================================================ FILE: spec/compiler/crystal/tools/doc/doc_renderer_spec.cr ================================================ require "../../../spec_helper" private def assert_code_link(obj, before, after = before) renderer = Doc::MarkdDocRenderer.new(obj, Markd::Options.new) renderer.expand_code_links(before).should eq(after) end private def it_renders(context, input, output, file = __FILE__, line = __LINE__) it "renders #{input.inspect}", file, line do c = context c ||= begin program = Program.new generator = Doc::Generator.new(program, [""]) generator.type(program) end options = Markd::Options.new document = Markd::Parser.parse(input, options) renderer = Doc::MarkdDocRenderer.new(c, options) renderer.render(document).chomp.should eq(output), file: file, line: line end end describe Doc::MarkdDocRenderer do describe "expand_code_links" do program = semantic(<<-CRYSTAL, wants_doc: true).program class Base def foo end def bar end def self.baz end def foo2(a, b) end def foo3(a, b, c) end def que? end def one!(one) end def <=(other) end class Nested CONST = true def foo end end end class Sub < Base def foo end end class A def foo; end def bar; end def self.baz; end end CRYSTAL generator = Doc::Generator.new(program, [""]) base = generator.type(program.types["Base"]) base_foo = base.lookup_method("foo").not_nil! sub = generator.type(program.types["Sub"]) sub_foo = sub.lookup_method("foo").not_nil! nested = generator.type(program.types["Base"].types["Nested"]) nested_foo = nested.lookup_method("foo").not_nil! single_char_class = generator.type(program.types["A"]) single_char_class_foo = single_char_class.lookup_method("foo").not_nil! it "finds sibling methods" do {base, base_foo}.each do |obj| assert_code_link(obj, "bar", %(#bar)) assert_code_link(obj, "baz", %(.baz)) end end it "finds sibling methods" do {base, base_foo}.each do |obj| assert_code_link(obj, "#bar", %(#bar)) assert_code_link(obj, ".baz", %(.baz)) end end it "matches methods on single-character class names" do {single_char_class, single_char_class_foo}.each do |obj| assert_code_link(obj, "#bar", %(#bar)) assert_code_link(obj, ".baz", %(.baz)) end end it "doesn't spuriously match range literals" do {base, base_foo}.each do |obj| assert_code_link(obj, "(0..baz)") assert_code_link(obj, "(0...baz)") assert_code_link(obj, "0..baz") assert_code_link(obj, "0...baz") end end it "doesn't find substrings for methods" do assert_code_link(base_foo, "not bar") assert_code_link(base_foo, "bazzy") end it "doesn't find sibling methods of wrong type" do {base, base_foo}.each do |obj| assert_code_link(obj, "Wrong#bar") assert_code_link(obj, "Wrong.bar") end end it "doesn't find sibling methods with fake receiver" do {base, base_foo}.each do |obj| assert_code_link(obj, "wrong#bar") assert_code_link(obj, "wrong.bar") end end it "finds sibling methods with self receiver" do {base, base_foo}.each do |obj| assert_code_link(obj, "self.bar", %(self.bar)) end end it "doesn't find parents' methods" do {sub, sub_foo, nested, nested_foo}.each do |obj| assert_code_link(obj, "bar") assert_code_link(obj, "baz") end end it "doesn't find parents' methods" do {sub, sub_foo, nested, nested_foo}.each do |obj| assert_code_link(obj, "#bar") assert_code_link(obj, ".baz") end end it "doesn't match with different separator" do {base, base_foo}.each do |obj| assert_code_link(obj, ",baz") assert_code_link(obj, "Base:bar", %(Base:bar)) end end it "finds method with args" do {base, base_foo}.each do |obj| assert_code_link(obj, "foo2(a, b)", %(#foo2(a, b))) assert_code_link(obj, "#foo2(a, a)", %(#foo2(a, a))) assert_code_link(obj, "Base#foo2(a, a)", %(Base#foo2(a, a))) end end it "finds method with zero args" do {base, base_foo}.each do |obj| assert_code_link(obj, "bar()", %(#bar())) assert_code_link(obj, "#bar()", %(#bar())) assert_code_link(obj, "Base#bar()", %(Base#bar())) end end it "doesn't find method with wrong number of args" do {base, base_foo}.each do |obj| assert_code_link(obj, "#foo2(a, a, a, a)") assert_code_link(obj, "#bar(a)") end end it "doesn't find method with wrong number of args" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base#foo2(a)") assert_code_link(obj, "Base#bar(a)") end end it "finds method with unspecified args" do {base, base_foo}.each do |obj| assert_code_link(obj, "foo2", %(#foo2)) assert_code_link(obj, "#foo2", %(#foo2)) assert_code_link(obj, "Base#foo2", %(Base#foo2)) end end it "finds method with args even with empty brackets" do {base, base_foo}.each do |obj| assert_code_link(obj, "foo2()", %(#foo2())) assert_code_link(obj, "#foo2()", %(#foo2())) assert_code_link(obj, "Base#foo2()", %(Base#foo2())) end end it "finds method with question mark" do {base, base_foo}.each do |obj| assert_code_link(obj, "que?", %(#que?)) assert_code_link(obj, "#que?", %(#que?)) assert_code_link(obj, "Base#que?", %(Base#que?)) end end it "finds method with exclamation mark" do {base, base_foo}.each do |obj| assert_code_link(obj, "one!(one)", %(#one!(one))) assert_code_link(obj, "#one!(one)", %(#one!(one))) assert_code_link(obj, "Base#one!(one)", %(Base#one!(one))) end end it "finds operator method" do {base, base_foo}.each do |obj| assert_code_link(obj, "<=(other)", %(#<=(other))) assert_code_link(obj, "#<=(other)", %(#<=(other))) assert_code_link(obj, "Base#<=(other)", %(Base#<=(other))) end end it "finds operator method with unspecified args" do {base, base_foo}.each do |obj| assert_code_link(obj, "<=", %(#<=)) assert_code_link(obj, "#<=", %(#<=)) assert_code_link(obj, "Base#<=", %(Base#<=)) end end it "finds methods of a type" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base#bar", %(Base#bar)) assert_code_link(obj, "Base.baz", %(Base.baz)) end end it "finds method of an absolute type" do {base, base_foo}.each do |obj| assert_code_link(obj, "::Base::Nested#foo", %(::Base::Nested#foo)) assert_code_link(obj, "::Base.baz", %(::Base.baz)) end end pending "doesn't find wrong kind of sibling methods" do {base, base_foo}.each do |obj| assert_code_link(obj, ".bar") assert_code_link(obj, "#baz") end end pending "doesn't find wrong kind of methods" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base.bar") assert_code_link(obj, "Base#baz") end end it "finds multiple methods with brackets" do {base, base_foo}.each do |obj| assert_code_link(obj, "#foo2(a, a) and Base#foo3(a,b, c)", %(#foo2(a, a) and Base#foo3(a,b, c))) end end it "finds types from base" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base and Sub and Nested", %(Base and Sub and Nested)) end end it "finds types from nested" do {nested, nested_foo}.each do |obj| assert_code_link(obj, "Base and Sub and Nested", %(Base and Sub and Nested)) end end it "finds constant" do {base, base_foo}.each do |obj| assert_code_link(obj, "Nested::CONST", %(Nested::CONST)) end end it "finds nested type" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base::Nested", %(Base::Nested)) end end it "finds absolute type" do {base, base_foo}.each do |obj| assert_code_link(obj, "::Base::Nested", %(::Base::Nested)) end end it "doesn't find wrong absolute type" do {base, base_foo}.each do |obj| assert_code_link(obj, "::Nested") end end it "doesn't find type not at word boundary" do {base, base_foo}.each do |obj| assert_code_link(obj, "aBase") end end it "finds multiple kinds of things" do {base, base_foo}.each do |obj| assert_code_link(obj, "Base#foo2(a, a) and #foo3 and Base", %(Base#foo2(a, a) and #foo3 and Base)) end end it "does not break when referencing lib type (#9928)" do program = semantic("lib LibFoo; BAR = 0; end", wants_doc: true).program generator = Doc::Generator.new(program, [""]) # TODO: There should not be a link to LibFoo::Bar in the first place # because LibFoo is undocumented assert_code_link(generator.type(program), "LibFoo::BAR", %(LibFoo::BAR)) end end describe "renders code blocks" do it_renders nil, "```crystal\nHello\nWorld\n```", %(
Hello\nWorld
) it_renders nil, "```cr\nHello\nWorld\n```", %(
Hello\nWorld
) it_renders nil, "```\nHello\nWorld\n```", %(
Hello\nWorld
) end describe "renders code spans" do it_renders nil, "`