├── .githooks └── pre-commit ├── .github └── workflows │ ├── nightly-release.yml │ └── onyx-build.yml ├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.md ├── bin ├── install.sh ├── onyx-js ├── onyx-loader.js └── onyx-thread.js ├── build.bat ├── build.sh ├── compiler ├── README.md ├── build.sh ├── include │ ├── astnodes.h │ ├── doc.h │ ├── errors.h │ ├── lex.h │ ├── parser.h │ ├── types.h │ ├── utils.h │ └── wasm_emit.h └── src │ ├── astnodes.c │ ├── builtins.c │ ├── checker.c │ ├── clone.c │ ├── doc.c │ ├── entities.c │ ├── errors.c │ ├── lex.c │ ├── onyx.c │ ├── onyx_run_standalone.c │ ├── onyxrun.c │ ├── parser.c │ ├── polymorph.h │ ├── symres.c │ ├── types.c │ ├── utils.c │ ├── wasm_emit.c │ ├── wasm_intrinsics.h │ ├── wasm_output.h │ ├── wasm_runtime.c │ └── wasm_type_table.h ├── core ├── alloc │ ├── alloc.onyx │ ├── arena.onyx │ ├── atomic.onyx │ ├── fixed.onyx │ ├── gc.onyx │ ├── heap.onyx │ ├── logging.onyx │ ├── memdebug.onyx │ ├── pool.onyx │ └── ring.onyx ├── builtin.onyx ├── container │ ├── array.onyx │ ├── avl_tree.onyx │ ├── bucket_array.onyx │ ├── heap.onyx │ ├── iter.onyx │ ├── list.onyx │ ├── map.onyx │ ├── optional.onyx │ ├── pair.onyx │ ├── result.onyx │ ├── set.onyx │ └── slice.onyx ├── conv │ ├── conv.onyx │ ├── format.onyx │ └── parse.onyx ├── doc │ └── doc.onyx ├── encoding │ ├── base64.onyx │ ├── csv.onyx │ ├── hex.onyx │ ├── ini.onyx │ ├── json │ │ ├── decoder.onyx │ │ ├── encoder.onyx │ │ ├── parser.onyx │ │ ├── tokenizer.onyx │ │ └── types.onyx │ ├── kdl │ │ ├── encoder.onyx │ │ ├── kdl.onyx │ │ ├── kql.onyx │ │ ├── parser.onyx │ │ └── utils.onyx │ ├── osad.onyx │ └── utf8.onyx ├── hash │ ├── hash.onyx │ ├── md5.onyx │ └── sha256.onyx ├── intrinsics │ ├── atomics.onyx │ ├── onyx.onyx │ ├── simd.onyx │ ├── type_interfaces.onyx │ └── wasm.onyx ├── io │ ├── binary.onyx │ ├── binary_reader.onyx │ ├── io.onyx │ ├── reader.onyx │ ├── stdio.onyx │ ├── stream.onyx │ └── writer.onyx ├── math │ └── math.onyx ├── memory │ └── memory.onyx ├── misc │ ├── any_utils.onyx │ ├── arg_parse.onyx │ └── method_ops.onyx ├── module.onyx ├── net │ ├── net.onyx │ └── tcp.onyx ├── onyx │ ├── cbindgen.onyx │ ├── cptr.onyx │ └── fault_handling.onyx ├── operations.onyx ├── os │ ├── dir.onyx │ ├── env.onyx │ ├── file.onyx │ ├── os.onyx │ ├── path.onyx │ ├── process.onyx │ └── tty.onyx ├── random │ └── random.onyx ├── runtime │ ├── build_opts.onyx │ ├── common.onyx │ ├── default_link_options.onyx │ ├── info │ │ ├── foreign_blocks.onyx │ │ ├── global_tags.onyx │ │ ├── helper.onyx │ │ ├── proc_tags.onyx │ │ ├── stack_trace.onyx │ │ └── types.onyx │ └── platform │ │ ├── js │ │ └── platform.onyx │ │ ├── onyx │ │ ├── env.onyx │ │ ├── fs.onyx │ │ ├── net.onyx │ │ └── platform.onyx │ │ └── wasi │ │ ├── platform.onyx │ │ ├── wasi_defs.onyx │ │ ├── wasi_env.onyx │ │ ├── wasi_fs.onyx │ │ ├── wasix_defs.onyx │ │ ├── wasix_misc.onyx │ │ └── wasix_net.onyx ├── string │ ├── buffer.onyx │ ├── char_utils.onyx │ ├── string.onyx │ └── string_pool.onyx ├── sync │ ├── barrier.onyx │ ├── condition_variable.onyx │ ├── mutex.onyx │ ├── once.onyx │ └── semaphore.onyx ├── test │ └── testing.onyx ├── threads │ └── thread.onyx └── time │ ├── date.onyx │ └── time.onyx ├── docs ├── bugs ├── ideas │ ├── ditching_wasi.md │ ├── doc_format.md │ ├── high_level_goals.md │ ├── interfaces.onyx │ ├── link_options.md │ ├── mapped_directories.md │ ├── module_thoughts │ ├── multi-pointers.md │ ├── platform_layer.md │ ├── pluggable_modules.md │ ├── shipping.md │ ├── struct_asm_rewrite.md │ ├── tagged_unions.md │ └── templated_projects.md ├── logos │ ├── logo-new-256.ico │ ├── logo-new-256.png │ ├── logo-new-32.png │ ├── logo-new-512.png │ ├── logo-new.png │ ├── logo.ico │ ├── logo.png │ ├── logo.svg │ ├── logo_256.png │ └── logo_512.png ├── old │ ├── builtins.md │ ├── plan │ └── spec ├── symbol_info.md └── todo ├── examples ├── 01_hello_world.onyx ├── 02_variables.onyx ├── 03_basics.onyx ├── 04_fixed_arrays.onyx ├── 05_slices.onyx ├── 06_dynamic_arrays.onyx ├── 07_structs.onyx ├── 08_enums.onyx ├── 09_for_loops.onyx ├── 10_switch_statements.onyx ├── 11_map.onyx ├── 12_varargs.onyx ├── 13_use_keyword.onyx ├── 14_overloaded_procs.onyx ├── 15_polymorphic_procs.onyx ├── 16_pipe_operator.onyx ├── 17_operator_overload.onyx ├── 18_macros.onyx ├── 19_do_blocks.onyx ├── 20_auto_return.onyx ├── 21_quick_functions.onyx ├── 22_interfaces.onyx └── 50_misc.onyx ├── interpreter ├── build.sh ├── include │ ├── ovm_debug.h │ ├── ovm_wasm.h │ ├── vm.h │ └── vm_codebuilder.h └── src │ ├── debug │ ├── debug_host.c │ ├── debug_info.c │ ├── debug_info_builder.c │ ├── debug_runtime_values.c │ └── debug_thread.c │ ├── ovmwasm.c │ ├── vm │ ├── code_builder.c │ ├── disasm.c │ ├── program_loader.c │ ├── vm.c │ └── vm_instrs.h │ └── wasm │ ├── config.c │ ├── engine.c │ ├── extern.c │ ├── frame.c │ ├── func.c │ ├── global.c │ ├── instance.c │ ├── memory.c │ ├── module.c │ ├── module_parsing.h │ ├── ref.c │ ├── store.c │ ├── table.c │ ├── trap.c │ ├── type.c │ └── value.c ├── misc ├── cloc_onyx_def ├── icon_resource.rc ├── onyx-linux.sublime-build ├── onyx-mode.el ├── onyx-windows.sublime-build ├── onyx.sublime-syntax ├── onyx.tmPreferences ├── onyx.vim ├── onyx_compiler.vim └── vscode │ ├── LICENSE │ ├── debugAdapter.ts │ ├── extension.ts │ ├── language-configuration.json │ ├── logo-icon.png │ ├── logo.png │ ├── onyx-0.0.4.vsix │ ├── onyx-0.1.0.vsix │ ├── onyx-0.1.1.vsix │ ├── onyx-0.1.2.vsix │ ├── onyx-0.1.3.vsix │ ├── onyx-0.1.4.vsix │ ├── onyx-0.1.5.vsix │ ├── onyx-0.1.6.vsix │ ├── onyx-0.1.7.vsix │ ├── onyx-0.1.8.vsix │ ├── onyxlang-0.1.10.vsix │ ├── onyxlang-0.1.9.vsix │ ├── out │ ├── debugAdapter.js │ ├── extension.js │ └── ovmDebug.js │ ├── ovmDebug.ts │ ├── package-lock.json │ ├── package.json │ ├── syntaxes │ └── onyx.tmLanguage │ ├── textmate-configuration.json │ └── tsconfig.json ├── runtime ├── README.md ├── build.sh ├── onyx_runtime.c └── src │ ├── ort_cptr.h │ ├── ort_directories.h │ ├── ort_files.h │ ├── ort_net_linux.h │ ├── ort_net_windows.h │ ├── ort_os.h │ ├── ort_processes.h │ ├── ort_threads.h │ └── ort_tty.h ├── scripts ├── core_tests.onyx ├── default.json ├── dist.onyx ├── onyx-pkg.onyx └── run_tests.onyx ├── settings.sh ├── shared ├── LICENSE ├── include │ ├── bh.h │ ├── dyncall │ │ ├── dyncall.h │ │ ├── dyncall_args.h │ │ ├── dyncall_callback.h │ │ ├── dyncall_config.h │ │ ├── dyncall_macros.h │ │ ├── dyncall_signature.h │ │ ├── dyncall_types.h │ │ └── dyncall_value.h │ ├── onyx_library.h │ ├── small_windows.h │ ├── stb_ds.h │ ├── wasm.h │ └── wasmer.h └── lib │ ├── README.md │ ├── darwin_amd64 │ └── lib │ │ ├── libdyncall_s.a │ │ └── libdyncallback_s.a │ ├── darwin_arm64 │ └── lib │ │ ├── libdyncall_s.a │ │ ├── libdyncallback_s.a │ │ └── libovmwasm.a │ ├── darwin_x86_64 │ └── lib │ │ ├── libdyncall_s.a │ │ └── libdyncallback_s.a │ ├── linux_aarch64 │ └── lib │ │ └── libwasmer.so │ ├── linux_x86_64 │ └── lib │ │ ├── libdyncall_s.a │ │ └── libdyncallback_s.a │ └── windows_x86_64 │ └── lib │ └── wasmer.lib └── tests ├── aoc-2020 ├── day1 ├── day1.onyx ├── day10 ├── day10.onyx ├── day11 ├── day11.onyx ├── day12 ├── day12.onyx ├── day13 ├── day13.onyx ├── day14 ├── day14.onyx ├── day15 ├── day15.onyx ├── day16 ├── day16.onyx ├── day17 ├── day17.onyx ├── day18 ├── day18.onyx ├── day19 ├── day19.onyx ├── day2 ├── day2.onyx ├── day20 ├── day20.onyx ├── day21 ├── day21.onyx ├── day22 ├── day22.onyx ├── day23 ├── day23.onyx ├── day24 ├── day24.onyx ├── day25 ├── day25.onyx ├── day3 ├── day3.onyx ├── day4 ├── day4.onyx ├── day5 ├── day5.onyx ├── day6 ├── day6.onyx ├── day7 ├── day7.onyx ├── day8 ├── day8.onyx ├── day9 ├── day9.onyx └── input │ ├── day1.txt │ ├── day10.txt │ ├── day11.txt │ ├── day12.txt │ ├── day13.txt │ ├── day14.txt │ ├── day15.txt │ ├── day16.txt │ ├── day17.txt │ ├── day18.txt │ ├── day19.txt │ ├── day2.txt │ ├── day20.txt │ ├── day21.txt │ ├── day22.txt │ ├── day24.txt │ ├── day25.txt │ ├── day3.txt │ ├── day4.txt │ ├── day5.txt │ ├── day6.txt │ ├── day7.txt │ ├── day8.txt │ └── day9.txt ├── aoc-2021 ├── day01 ├── day01.onyx ├── day02 ├── day02.onyx ├── day03 ├── day03.onyx ├── day04 ├── day04.onyx ├── day05 ├── day05.onyx ├── day06 ├── day06.onyx ├── day07 ├── day07.onyx ├── day08 ├── day08.onyx ├── day09 ├── day09.onyx ├── day10 ├── day10.onyx ├── day11 ├── day11.onyx ├── day12 ├── day12.onyx ├── day13 ├── day13.onyx ├── day14 ├── day14.onyx ├── day15 ├── day15.onyx ├── day16 ├── day16.onyx ├── day17 ├── day17.onyx ├── day18 ├── day18.onyx ├── day21 ├── day21.onyx └── input │ ├── day01.txt │ ├── day02.txt │ ├── day03.txt │ ├── day04.txt │ ├── day05.txt │ ├── day06.txt │ ├── day07.txt │ ├── day08.txt │ ├── day09.txt │ ├── day10.txt │ ├── day11.txt │ ├── day12.txt │ ├── day13.txt │ ├── day14.txt │ ├── day15.txt │ ├── day16.txt │ ├── day17.txt │ ├── day18.txt │ └── day21.txt ├── array_accessors ├── array_accessors.onyx ├── array_programming ├── array_programming.onyx ├── array_struct_robustness ├── array_struct_robustness.onyx ├── arrow_notation ├── arrow_notation.onyx ├── atomics ├── atomics.onyx ├── auto_poly ├── auto_poly.onyx ├── avl_test ├── avl_test.onyx ├── baked_parameters ├── baked_parameters.onyx ├── better_field_accesses ├── better_field_accesses.onyx ├── bucket_array ├── bucket_array.onyx ├── bugs ├── anonymous_struct_defaults ├── anonymous_struct_defaults.onyx ├── array_lengths ├── array_lengths.onyx ├── autopoly_limits ├── autopoly_limits.onyx ├── defer_block_in_macro ├── defer_block_in_macro.onyx ├── double_polymorph_yield_error ├── double_polymorph_yield_error.onyx ├── fallthrough_defer_interaction ├── fallthrough_defer_interaction.onyx ├── format_negative_other_base ├── format_negative_other_base.onyx ├── injecting_global_symbol_order ├── injecting_global_symbol_order.onyx ├── macro_auto_return_not_resolved ├── macro_auto_return_not_resolved.onyx ├── method_call_source_double ├── method_call_source_double.onyx ├── namespace_aliasing ├── namespace_aliasing.onyx ├── print_formatters └── print_formatters.onyx ├── caller_location ├── caller_location.onyx ├── char_literals ├── char_literals.onyx ├── code_block_captures ├── code_block_captures.onyx ├── compile_time_procedures ├── compile_time_procedures.onyx ├── complicated_polymorph ├── complicated_polymorph.onyx ├── defer_with_continue ├── defer_with_continue.onyx ├── defined_test ├── defined_test.onyx ├── distinct_types ├── distinct_types.onyx ├── do_block_single_statement ├── do_block_single_statement.onyx ├── dyn_str ├── dyn_str.onyx ├── first_class_optional ├── first_class_optional.onyx ├── float_parsing ├── float_parsing.onyx ├── for_loop_indexes ├── for_loop_indexes.onyx ├── hello_world ├── hello_world.onyx ├── hex_autocoder ├── hex_autocoder.onyx ├── i32map ├── i32map.onyx ├── if_expressions ├── if_expressions.onyx ├── ignored_return_values ├── ignored_return_values.onyx ├── implicit_initialize_locals ├── implicit_initialize_locals.onyx ├── init_procedures ├── init_procedures.onyx ├── interface_scopes ├── interface_scopes.onyx ├── interfaces ├── interfaces.onyx ├── json_test ├── json_test.onyx ├── lazy_iterators ├── lazy_iterators.onyx ├── left_to_right_order ├── left_to_right_order.onyx ├── linked_lists ├── linked_lists.onyx ├── lists_comprehensive ├── lists_comprehensive.onyx ├── map_enum_key ├── map_enum_key.onyx ├── multiple_returns_robustness ├── multiple_returns_robustness.onyx ├── named_arguments_test ├── named_arguments_test.onyx ├── nested-if-exprs ├── nested-if-exprs.onyx ├── nested_array_literals ├── nested_array_literals.onyx ├── new_printf ├── new_printf.onyx ├── new_struct_behaviour ├── new_struct_behaviour.onyx ├── no_types ├── no_types.onyx ├── operator_overload ├── operator_overload.onyx ├── operators_as_methods ├── operators_as_methods.onyx ├── osad_test ├── osad_test.onyx ├── overload_precedence ├── overload_precedence.onyx ├── overload_return_type ├── overload_return_type.onyx ├── overload_with_autocast ├── overload_with_autocast.onyx ├── parallel_for.onyx ├── persist_locals ├── persist_locals.onyx ├── poly_struct_in_type_info ├── poly_struct_in_type_info.onyx ├── poly_structs_with_values ├── poly_structs_with_values.onyx ├── polymorphic_array_lengths ├── polymorphic_array_lengths.onyx ├── remove_test ├── remove_test.onyx ├── sets ├── sets.onyx ├── stdlib ├── base64 ├── base64.onyx ├── conv_parse ├── conv_parse.onyx ├── os_path └── os_path.onyx ├── string_stream_test ├── string_stream_test.onyx ├── struct_robustness ├── struct_robustness.onyx ├── struct_use_pointer_member ├── struct_use_pointer_member.onyx ├── structure_method_tag ├── structure_method_tag.onyx ├── switch_expressions ├── switch_expressions.onyx ├── switch_using_equals ├── switch_using_equals.onyx ├── tagged_globals ├── tagged_globals.onyx ├── tagged_unions ├── tagged_unions.onyx ├── utf8_test ├── utf8_test.onyx ├── vararg_test ├── vararg_test.onyx ├── where_clauses └── where_clauses.onyx /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ! grep -Rns nocheckin compiler interpretter runtime core -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.o 2 | **/*.DS_Store 3 | *.o 4 | tags 5 | *.wasm 6 | session.vim 7 | *.sublime-project 8 | *.sublime-workspace 9 | *.code-workspace 10 | *.pdb 11 | *.ilk 12 | *.obj 13 | *.exe 14 | *.dll 15 | *.rdbg 16 | tmp/ 17 | .vimspector.json 18 | .vscode/ 19 | dist/ 20 | **/node_modules/ 21 | onyx-lsp.ini 22 | shared/lib/linux_x86_64/lib/libovmwasm.a 23 | bin/onyx-run 24 | bin/onyx 25 | releases/ 26 | compiler/onyx 27 | runtime/onyx_runtime.so 28 | runtime/onyx_runtime.dylib 29 | runtime/onyx_runtime.dll 30 | .clangd 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Brendan Hansen 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Onyx 2 | 3 | [![Workflow](https://github.com/onyx-lang/onyx/workflows/Build%20and%20Test/badge.svg)](https://github.com/onyx-lang/onyx/actions) 4 | [![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) 5 | 6 | A simple, yet powerful language for WebAssembly. 7 | 8 | [Try Online](https://try.onyxlang.io/) | 9 | [Read the Docs](https://onyxlang.io/docs/) | 10 | [Join the Discord](https://discord.gg/bhuN36dqj7) 11 | -------------------------------------------------------------------------------- /bin/onyx-thread.js: -------------------------------------------------------------------------------- 1 | 2 | function onyx_decode_text(ptr, len) { 3 | let v = new DataView(self.ONYX_MEMORY.buffer); 4 | 5 | let s = ""; 6 | for (let i = 0; i < len; i++) { 7 | s += String.fromCharCode(v.getUint8(ptr + i)); 8 | } 9 | 10 | return s; 11 | } 12 | 13 | 14 | self.onmessage = function (msg) { 15 | const data = msg.data; 16 | 17 | let import_object = {}; 18 | for (let k of Object.keys(data.imports)) { 19 | import_object[k] = {}; 20 | for (let v of data.imports[k]) { 21 | import_object[k][v] = function(a, b, c, d, e, f, g, h, i, j) { 22 | console.error("ATTEMPT TO CALL MAIN THREAD FUNCTION FROM WORKER THREAD! " + v + "." + k); 23 | } 24 | } 25 | } 26 | 27 | import_object.host.print_str = function(ptr, len) { console.log(onyx_decode_text(ptr, len)); }; 28 | import_object.host.exit = function() { debugger; }; 29 | import_object.onyx = { memory: data.memory }; 30 | 31 | WebAssembly.instantiate(new Uint8Array(data.wasm_bytes), import_object) 32 | .then(function(res) { 33 | self.ONYX_MEMORY = data.memory; 34 | 35 | res.instance.exports._thread_start(data.thread_id, data.tls_base, data.stack_base, data.funcidx, data.closureptr, data.closuresize, data.dataptr); 36 | res.instance.exports._thread_exit(data.thread_id); 37 | }); 38 | , 39 | -------------------------------------------------------------------------------- /compiler/README.md: -------------------------------------------------------------------------------- 1 | # Onyx Compiler 2 | 3 | This part of the repo provides the `onyx` compiler, as well 4 | as the `onyx-run` binary. 5 | 6 | -------------------------------------------------------------------------------- /compiler/include/doc.h: -------------------------------------------------------------------------------- 1 | #ifndef ONYXDOC_H 2 | #define ONYXDOC_H 3 | 4 | #include "bh.h" 5 | #include "astnodes.h" 6 | 7 | // Onyx Documentation generation 8 | 9 | void onyx_docs_submit(OnyxDocInfo *docs, AstBinding *binding); 10 | void onyx_docs_emit_odoc(const char *dest); 11 | 12 | 13 | // Tag generation 14 | 15 | void onyx_docs_emit_tags(char *dest); 16 | 17 | 18 | 19 | // Symbol info file generation 20 | 21 | typedef struct SymbolInfo SymbolInfo; 22 | struct SymbolInfo { 23 | u32 id; 24 | u32 file_id; 25 | u32 line; 26 | u32 column; 27 | OnyxToken *documentation; 28 | }; 29 | 30 | typedef struct SymbolResolution SymbolResolution; 31 | struct SymbolResolution { 32 | u32 file_id; 33 | u32 line; 34 | u32 column; 35 | u32 length; 36 | u32 symbol_id; 37 | }; 38 | 39 | typedef struct SymbolInfoTable SymbolInfoTable; 40 | struct SymbolInfoTable { 41 | // File name -> file id 42 | Table(u32) files; 43 | u32 next_file_id; 44 | 45 | // Symbol id -> symbol info 46 | bh_arr(SymbolInfo) symbols; 47 | u32 next_symbol_id; 48 | 49 | bh_arr(SymbolResolution) symbols_resolutions; 50 | 51 | // Node * -> symbol_id 52 | bh_imap node_to_id; 53 | }; 54 | 55 | void onyx_docs_emit_symbol_info(const char *dest); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /compiler/include/errors.h: -------------------------------------------------------------------------------- 1 | #ifndef ONYXERRORS_H 2 | #define ONYXERRORS_H 3 | 4 | #include "bh.h" 5 | #include "lex.h" 6 | 7 | #include 8 | 9 | typedef enum OnyxErrorRank { 10 | Error_Undefined = 0, 11 | Error_Other = 1, 12 | Error_Warning = 2, 13 | Error_Waiting_On = 3, 14 | Error_Critical = 4, 15 | } OnyxErrorRank; 16 | 17 | typedef struct OnyxError { 18 | OnyxFilePos pos; 19 | OnyxErrorRank rank; 20 | char *text; 21 | } OnyxError; 22 | 23 | typedef struct OnyxErrors { 24 | bh_arena msg_arena; 25 | bh_allocator msg_alloc; 26 | 27 | // NOTE: Pointer to a array of all the loaded files. 28 | bh_arr(bh_file_contents)* file_contents; 29 | 30 | bh_arr(OnyxError) errors; 31 | } OnyxErrors; 32 | 33 | extern OnyxErrors msgs; 34 | 35 | void onyx_errors_init(bh_arr(bh_file_contents)* files); 36 | void onyx_errors_enable(); 37 | void onyx_errors_disable(); 38 | b32 onyx_errors_are_enabled(); 39 | void onyx_submit_error(OnyxError error); 40 | void onyx_report_error(OnyxFilePos pos, OnyxErrorRank rank, char * format, ...); 41 | void onyx_submit_warning(OnyxError error); 42 | void onyx_report_warning(OnyxFilePos pos, char* format, ...); 43 | void onyx_errors_print(); 44 | b32 onyx_has_errors(); 45 | void onyx_clear_errors(); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /compiler/src/onyx_run_standalone.c: -------------------------------------------------------------------------------- 1 | #define BH_DEFINE 2 | #define BH_NO_TABLE 3 | #define STB_DS_IMPLEMENTATION 4 | #include "bh.h" 5 | 6 | #include "wasm_emit.h" 7 | 8 | extern const char _binary__tmp_out_wasm_start; 9 | extern const char _binary__tmp_out_wasm_end; 10 | 11 | void onyx_run_initialize(int debug); 12 | int onyx_run_wasm(bh_buffer, int argc, char **argv); 13 | 14 | int main(int argc, char *argv[]) { 15 | onyx_run_initialize(0); 16 | 17 | bh_buffer data; 18 | data.data = (char *) &_binary__tmp_out_wasm_start; 19 | data.length = &_binary__tmp_out_wasm_end - &_binary__tmp_out_wasm_start; 20 | return onyx_run_wasm(data, argc - 1, argv + 1); 21 | } 22 | -------------------------------------------------------------------------------- /compiler/src/onyxrun.c: -------------------------------------------------------------------------------- 1 | #define BH_DEFINE 2 | #define BH_NO_TABLE 3 | #define STB_DS_IMPLEMENTATION 4 | #include "bh.h" 5 | 6 | #include "wasm_emit.h" 7 | 8 | int main(int argc, char *argv[]) { 9 | i32 wasm_file_idx = 1; 10 | if (argc < 2) { 11 | fprintf(stderr, "Expected a WASM file to run.\n"); 12 | return 1; 13 | } 14 | 15 | b32 debug = 0; 16 | if (!strcmp(argv[1], "--debug")) { 17 | debug = 1; 18 | wasm_file_idx = 2; 19 | } 20 | 21 | if (debug && argc < 3) { 22 | fprintf(stderr, "Expected a WASM file to run.\n"); 23 | return 1; 24 | } 25 | 26 | onyx_run_initialize(debug); 27 | 28 | bh_file wasm_file; 29 | bh_file_error err = bh_file_open(&wasm_file, argv[wasm_file_idx]); 30 | if (err != BH_FILE_ERROR_NONE) { 31 | fprintf(stderr, "Failed to open file %s", argv[wasm_file_idx]); 32 | return 1; 33 | } 34 | 35 | bh_file_contents wasm_data = bh_file_read_contents(bh_heap_allocator(), &wasm_file); 36 | bh_file_close(&wasm_file); 37 | 38 | bh_buffer data; 39 | data.data = wasm_data.data; 40 | data.length = wasm_data.length; 41 | return onyx_run_wasm(data, argc - 1 - debug, argv + 1 + debug); 42 | } 43 | -------------------------------------------------------------------------------- /core/alloc/atomic.onyx: -------------------------------------------------------------------------------- 1 | package core.alloc.atomic 2 | #package_doc """ 3 | AtomicAllocator wraps another allocator in a mutex, 4 | ensuring that every allocation is thread-safe. This 5 | is not needed for the general purpose heap allocator, 6 | as that already has a thread-safe implementation. 7 | """ 8 | 9 | // This can only be used when the core.sync package exists. 10 | #if #defined(package core.sync) { 11 | 12 | 13 | use core.alloc 14 | use core.sync 15 | 16 | #doc """ 17 | Stores internal details used by the atomic allocator. 18 | 19 | Simply the wrapped allocator and the mutex. 20 | """ 21 | AtomicAllocator :: struct { 22 | a: Allocator; 23 | m: sync.Mutex; 24 | } 25 | 26 | #doc """ 27 | Creates a new AtomicAllocator over an existing allocator. 28 | """ 29 | make :: (a: Allocator) -> AtomicAllocator { 30 | atomic: AtomicAllocator = .{ a = a }; 31 | 32 | sync.mutex_init(&atomic.m); 33 | 34 | return atomic; 35 | } 36 | 37 | #doc """ 38 | Makes an allocator out of the atomic allocator state. 39 | """ 40 | make_allocator :: (atomic: &AtomicAllocator) => 41 | Allocator.{ atomic, atomic_alloc }; 42 | 43 | #overload 44 | alloc.as_allocator :: make_allocator 45 | 46 | 47 | #local 48 | atomic_alloc :: (atomic: &AtomicAllocator, aa: AllocationAction, size: u32, align: u32, oldptr: rawptr) -> rawptr { 49 | sync.scoped_mutex(&atomic.m); 50 | return atomic.a.func(atomic.a.data, aa, size, align, oldptr); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /core/alloc/fixed.onyx: -------------------------------------------------------------------------------- 1 | package core.alloc.fixed 2 | #package_doc """ 3 | This allocator is very simple. It is simply a bump allocator from 4 | a fixed size buffer. It cannot free or resize, and will return null 5 | when it has used all memory in the buffer given to it. 6 | 7 | This kind of allocator is useful for temporary string building or 8 | similar circumstances, where you know that the needed memory size 9 | will not be exceeded, but you don't what to deal with potential 10 | slowness of a general heap allocator. By using this allocator, you 11 | can continue to use the same code that does allocations like normal, 12 | but can get the speed increase of a simple allocation strategy. 13 | """ 14 | 15 | use core 16 | 17 | 18 | FixedAllocator :: struct { 19 | buffer: [] u8; 20 | end: u32; 21 | } 22 | 23 | #local 24 | fixed_allocator_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32, oldptr: rawptr) -> rawptr { 25 | fa_data := cast(&FixedAllocator) data; 26 | 27 | if aa != .Alloc do return null; 28 | if size > fa_data.buffer.count - fa_data.end do return null; 29 | 30 | aligned_end := cast(u32) core.memory.align(fa_data.end, align); 31 | defer fa_data.end = aligned_end + size; 32 | 33 | return fa_data.buffer.data + aligned_end; 34 | } 35 | 36 | make :: (buffer: [] u8) => FixedAllocator.{ buffer, 0 } 37 | 38 | #match core.alloc.as_allocator make_allocator 39 | make_allocator :: (fa_data: &FixedAllocator) => Allocator.{ 40 | func = fixed_allocator_proc, 41 | data = fa_data, 42 | } 43 | 44 | reset :: (data: &FixedAllocator) { 45 | data.end = 0; 46 | } 47 | -------------------------------------------------------------------------------- /core/alloc/logging.onyx: -------------------------------------------------------------------------------- 1 | package core.alloc.log 2 | #package_doc """ 3 | This allocator simply wraps another allocator and 4 | prints every allocation/deallocation made by that 5 | allocator. 6 | """ 7 | 8 | 9 | use core 10 | use runtime 11 | 12 | #local 13 | Allocation_Action_Strings := str.[ 14 | "alloc", 15 | "free", 16 | "resize", 17 | ]; 18 | 19 | #local 20 | logging_allocator_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32, oldptr: rawptr) -> rawptr { 21 | allocator := cast(&Allocator) data; 22 | res := allocator.func(allocator.data, aa, size, align, oldptr); 23 | 24 | use core { tprintf } 25 | msg := tprintf("{} = {}(size={}, align={}, oldptr={})", 26 | res, Allocation_Action_Strings[cast(u32) aa], size, align, oldptr); 27 | 28 | log(.Info, "Core", msg); 29 | 30 | trace := runtime.info.get_stack_trace(); 31 | defer if trace do delete(&trace); 32 | for trace { 33 | log(.Info, "Core", tprintf("in {} ({}:{})", it.info.func_name, it.info.file, it.current_line)); 34 | } 35 | 36 | return res; 37 | } 38 | 39 | logging_allocator :: (alloc: &Allocator) -> Allocator { 40 | return Allocator.{ 41 | func = logging_allocator_proc, 42 | data = alloc, 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /core/alloc/ring.onyx: -------------------------------------------------------------------------------- 1 | package core.alloc.ring 2 | #package_doc """ 3 | This allocator is great for temporary memory, such as returning 4 | a pointer from a function, or storing a formatted string. The 5 | memory allocated using this allocator does not need to be freed. 6 | The idea is that as you keep allocating you will "wrap around" 7 | and start writing over memory that was allocated before. For this 8 | reason, it is not safe to use this for any kind of permanent 9 | allocation. Also, be wary that you provide this allocator with 10 | a buffer big enough to store as much data as you are going to need 11 | at any given time. 12 | """ 13 | 14 | use core 15 | 16 | RingState :: struct { 17 | base_ptr : rawptr; 18 | size : u32; 19 | curr : u32; 20 | } 21 | 22 | #local 23 | ring_alloc_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32, oldptr: rawptr) -> rawptr { 24 | ss := cast(&RingState) data; 25 | 26 | if aa == .Alloc { 27 | retval := null; 28 | if ss.curr + size < ss.size { 29 | retval = cast([&] u8) ss.base_ptr + ss.curr; 30 | ss.curr += size; 31 | } 32 | elseif size <= ss.size { 33 | retval = ss.base_ptr; 34 | ss.curr = size; 35 | } 36 | 37 | return retval; 38 | } 39 | 40 | return null; 41 | } 42 | 43 | make :: (buffer: [] u8) -> RingState { 44 | return .{ 45 | base_ptr = buffer.data, 46 | size = buffer.count, 47 | curr = 0, 48 | }; 49 | } 50 | 51 | #match core.alloc.as_allocator make_allocator 52 | make_allocator :: (rs: &RingState) -> Allocator { 53 | return .{ 54 | func = ring_alloc_proc, 55 | data = rs, 56 | }; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /core/container/pair.onyx: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | 4 | #doc """ 5 | A `Pair` represents a pair of values of heterogenous types. 6 | This structure does not do much on its own; however, it 7 | is useful because provides overloads for formatting, hashing 8 | and equality. This means you can use a `Pair(T, R)` as a key 9 | for a Map or Set out of the box, provided T and R are hashable 10 | and equatable. 11 | """ 12 | @conv.Custom_Format.{#solidify _format {First_Type=First_Type, Second_Type=Second_Type}} 13 | Pair :: struct (First_Type: type_expr, Second_Type: type_expr) { 14 | first: First_Type; 15 | second: Second_Type; 16 | } 17 | 18 | #inject Pair { 19 | make :: macro (x: $X, y: $Y) => #this_package.Pair(X, Y).{x, y}; 20 | 21 | _format :: (output: &conv.Format_Output, format: &conv.Format, p: &Pair($First_Type, $Second_Type)) { 22 | conv.format(output, "({}, {})", p.first, p.second); 23 | } 24 | } 25 | 26 | #overload 27 | hash.hash :: (p: Pair($First_Type/hash.Hashable, $Second_Type/hash.Hashable)) => { 28 | h := 7; 29 | h += h << 5 + hash.hash(p.first); 30 | h += h << 5 + hash.hash(p.second); 31 | return h; 32 | } 33 | 34 | 35 | #operator == (p1, p2: Pair($First_Type/Equatable, $Second_Type/Equatable)) => { 36 | return p1.first == p2.first && p1.second == p2.second; 37 | } 38 | 39 | #operator != (p1, p2: Pair($First_Type/Equatable, $Second_Type/Equatable)) => { 40 | return !(p1.first == p2.first) || !(p1.second == p2.second); 41 | } 42 | 43 | #local Equatable :: interface (T: type_expr) { 44 | t as T; 45 | { t == t } -> bool; 46 | } 47 | -------------------------------------------------------------------------------- /core/encoding/hex.onyx: -------------------------------------------------------------------------------- 1 | package core.encoding.hex 2 | 3 | encode :: (s: str, allocator := context.allocator) -> str { 4 | #persist encode_map := u8.['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; 5 | 6 | new_str := make([] u8, s.count * 2, allocator); 7 | for i in s.count { 8 | new_str[2 * i + 0] = encode_map[(s[i] & 0xf0) >> 4]; 9 | new_str[2 * i + 1] = encode_map[s[i] & 0xf]; 10 | } 11 | 12 | return new_str; 13 | } 14 | 15 | decode :: (s: str, allocator := context.allocator) -> str { 16 | assert(s.count & 1 == 0, "Expected string of even length"); 17 | 18 | new_str := make([] u8, s.count >> 1, allocator); 19 | for i in range.{0, s.count, 2} { 20 | new_str[i >> 1] = ~~((digit_to_value(s[i + 0]) << 4) | (digit_to_value(s[i + 1]))); 21 | } 22 | 23 | return new_str; 24 | 25 | digit_to_value :: (it: u8) -> u32 { 26 | return ~~ switch it { 27 | case #char "0" .. #char "9" => it - #char "0"; 28 | case #char "a" .. #char "f" => it - #char "a" + 10; 29 | case #char "A" .. #char "F" => it - #char "A" + 10; 30 | case #default => 0; 31 | }; 32 | } 33 | } -------------------------------------------------------------------------------- /core/encoding/kdl/utils.onyx: -------------------------------------------------------------------------------- 1 | package core.encoding.kdl 2 | #allow_stale_code 3 | 4 | use core {string} 5 | 6 | #inject Value { 7 | as_str :: (v: Value) -> ? str { 8 | return v.data.String; 9 | } 10 | 11 | as_int :: (v: Value) -> ? i64 { 12 | return v.data.Number?.Integer; 13 | } 14 | 15 | as_float :: (v: Value) -> ? f64 { 16 | return v.data.Number?.Float; 17 | } 18 | 19 | as_bool :: (v: Value) -> ? bool { 20 | return v.data.Boolean; 21 | } 22 | } 23 | 24 | #inject Document { 25 | create_node :: (d: &Document, name: str) -> &Node { 26 | return d.allocator->move(Node.{ 27 | node = name, 28 | type_annotation = .None, 29 | values = make([..] Value, d.allocator), 30 | props = make(Map(str, Value), d.allocator), 31 | children = make([..] &Node, d.allocator) 32 | }); 33 | } 34 | } 35 | 36 | #inject Node { 37 | add_value :: (n: &Node, value: Value.Value_Data) { 38 | n.values << Value.{data = value}; 39 | } 40 | 41 | set_prop :: (n: &Node, name: str, value: Value.Value_Data) { 42 | n.props->put( 43 | string.alloc_copy(name, n.props.allocator), 44 | .{ data = value } 45 | ); 46 | } 47 | 48 | value :: (n: &Node, index := 0) -> ? Value { 49 | if index >= n.values.length do return .{}; 50 | 51 | return n.values[index]; 52 | } 53 | 54 | value_or_null :: (n: &Node, index := 0) -> Value { 55 | if index >= n.values.length do return .{ 56 | data = .{ Null = .{} } 57 | }; 58 | 59 | return n.values[index]; 60 | } 61 | } -------------------------------------------------------------------------------- /core/intrinsics/atomics.onyx: -------------------------------------------------------------------------------- 1 | package core.intrinsics.atomics 2 | 3 | // __atomic_wait is only valid for i32 and i64 4 | __atomic_wait :: (addr: &$T, value: T, timeout: i64 = -1) -> i32 #intrinsic --- 5 | __atomic_notify :: (addr: rawptr, maximum: i32 = 1) -> i32 #intrinsic --- 6 | 7 | __atomic_fence :: () -> void #intrinsic --- 8 | 9 | // These are only valid for the eight integer types (i8, u8, i16, u16, i32, u32, i64, u64) 10 | __atomic_load :: (addr: &$T) -> T #intrinsic --- 11 | __atomic_store :: (addr: &$T, value: T) -> void #intrinsic --- 12 | __atomic_add :: (addr: &$T, value: T) -> T #intrinsic --- 13 | __atomic_sub :: (addr: &$T, value: T) -> T #intrinsic --- 14 | __atomic_and :: (addr: &$T, value: T) -> T #intrinsic --- 15 | __atomic_or :: (addr: &$T, value: T) -> T #intrinsic --- 16 | __atomic_xor :: (addr: &$T, value: T) -> T #intrinsic --- 17 | __atomic_xchg :: (addr: &$T, value: T) -> T #intrinsic --- 18 | __atomic_cmpxchg :: (addr: &$T, compare: T, value: T) -> T #intrinsic --- 19 | -------------------------------------------------------------------------------- /core/intrinsics/onyx.onyx: -------------------------------------------------------------------------------- 1 | package core.intrinsics.onyx 2 | 3 | // 4 | // Special intrinsic function that initializes a value. 5 | // This is generally used on structure to execute their 6 | // default initializer expressions. 7 | __initialize :: (val: &$T) -> void #intrinsic --- 8 | 9 | // 10 | // Helpful macro to create an initialized value. 11 | // Mostly pointless now that T.{} does the same thing. 12 | init :: macro ($T: type_expr) -> T { 13 | __initialize :: __initialize 14 | 15 | val: T; 16 | __initialize(&val); 17 | return val; 18 | } 19 | -------------------------------------------------------------------------------- /core/intrinsics/type_interfaces.onyx: -------------------------------------------------------------------------------- 1 | package core.intrinsics.types 2 | 3 | // 4 | // Simple: bool, number, simd, pointer, enum 5 | // Number: int, float 6 | // Int: u8, .., u64 i8, .., i64 7 | // Float: f32 f64 8 | // Simd: v128 i8x16 i16x8 i32x4 i64x2 f32x4 f64x2 9 | // Pointer: &T rawptr 10 | // Compound: array, slice, struct 11 | // Array: [$N] $T 12 | // Slice: [] $T 13 | // Function: () -> void 14 | 15 | type_is_bool :: interface (T: type_expr) #intrinsic 16 | type_is_int :: interface (T: type_expr) #intrinsic 17 | type_is_float :: interface (T: type_expr) #intrinsic 18 | type_is_number :: interface (T: type_expr) #intrinsic 19 | type_is_simd :: interface (T: type_expr) #intrinsic 20 | type_is_pointer :: interface (T: type_expr) #intrinsic 21 | type_is_enum :: interface (T: type_expr) #intrinsic 22 | type_is_simple :: interface (T: type_expr) #intrinsic 23 | type_is_array :: interface (T: type_expr) #intrinsic 24 | type_is_slice :: interface (T: type_expr) #intrinsic 25 | type_is_struct :: interface (T: type_expr) #intrinsic 26 | type_is_compound :: interface (T: type_expr) #intrinsic 27 | type_is_function :: interface (T: type_expr) #intrinsic 28 | 29 | -------------------------------------------------------------------------------- /core/io/io.onyx: -------------------------------------------------------------------------------- 1 | package core.io 2 | 3 | Error :: enum { 4 | None :: 0x00; 5 | 6 | // The procedure is not implemented for this kind of stream. 7 | NotImplemented :: 0x01; 8 | 9 | // The stream reached the end. 10 | EOF :: 0x02; 11 | 12 | // The vtable was not set for this stream. 13 | NoVtable :: 0x03; 14 | 15 | // A seek was outside the bounds of the stream. 16 | OutOfBounds :: 0x04; 17 | 18 | // The file or stream was not found. 19 | NotFound :: 0x05; 20 | 21 | // The file or stream was not initialized correctly. 22 | BadFile :: 0x06; 23 | 24 | // Some underlying buffer used in stream processing is full. 25 | BufferFull :: 0x07; 26 | 27 | // While trying to read from a stream, multiple reads failed in a row. 28 | NoProgress :: 0x08; 29 | 30 | // Not possible to unread. 31 | InvalidUnread :: 0x09; 32 | 33 | // When reading from a stream, no data was read, but data will become available soon. 34 | ReadPending :: 0x0a; 35 | 36 | // When reading from a stream, no data was read, and data will not become available soon. 37 | ReadLater :: 0x0b; 38 | 39 | // A socket tried to connect to an endpoint and failed. 40 | ConnectFailed :: 0x0c; 41 | 42 | // Sockets only. Signals that no data was recieved from a non-blocking operation. 43 | NoData :: 0x0d; 44 | 45 | // Failed to create an object. 46 | CreationFailed :: 0x0e; 47 | 48 | // The operation failed. 49 | OperationFailed :: 0x0f; 50 | } 51 | -------------------------------------------------------------------------------- /core/onyx/fault_handling.onyx: -------------------------------------------------------------------------------- 1 | package core.os 2 | 3 | Fault_Handler :: struct { 4 | handle: (rawptr) -> void; 5 | ctx: rawptr; 6 | } 7 | 8 | register_fault_handler :: (ctx: rawptr, handle: (rawptr) -> void) { 9 | fault_handlers << .{ handle, ctx }; 10 | 11 | if !global_fault_handle_registered { 12 | assert(__register_cleanup(#export_name global_fault_handler), "Failed to register global fault handler"); 13 | global_fault_handle_registered = true; 14 | } 15 | } 16 | 17 | #local { 18 | #foreign "onyx_runtime" { 19 | __register_cleanup :: (name: str) -> bool --- 20 | } 21 | 22 | global_fault_handler :: () { 23 | for fault_handlers { 24 | it.handle(it.ctx); 25 | } 26 | } 27 | 28 | fault_handlers: [..] Fault_Handler 29 | global_fault_handle_registered := false; 30 | } 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /core/os/env.onyx: -------------------------------------------------------------------------------- 1 | package core.os 2 | 3 | use core.iter 4 | use runtime.platform { 5 | __get_all_env, 6 | __get_env 7 | } 8 | 9 | env_vars :: () -> Map(str, str) { 10 | return __get_all_env() 11 | |> iter.as_iter() 12 | |> iter.map(x => *x) 13 | |> iter.to_map(); 14 | } 15 | 16 | env :: (key: str) -> ? str { 17 | return __get_env(key); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /core/os/os.onyx: -------------------------------------------------------------------------------- 1 | package core.os 2 | 3 | use runtime 4 | 5 | #if !runtime.platform.Supports_Os { 6 | #error "Cannot include this file. Platform not supported."; 7 | } 8 | 9 | exit :: (exitcode: i32) { 10 | runtime.platform.__exit(exitcode); 11 | } 12 | 13 | #if #defined(runtime.platform.__sleep) { 14 | sleep :: runtime.platform.__sleep 15 | } 16 | 17 | #if #defined(runtime.platform.__time) { 18 | time :: runtime.platform.__time 19 | } else { 20 | time :: () => u64.{0}; 21 | } 22 | -------------------------------------------------------------------------------- /core/os/tty.onyx: -------------------------------------------------------------------------------- 1 | package core.os 2 | 3 | use runtime 4 | 5 | TTY_State :: struct { 6 | rows: i32; 7 | cols: i32; 8 | stdin_is_tty: bool; 9 | stdout_is_tty: bool; 10 | stderr_is_tty: bool; 11 | echo: bool; 12 | input_buffered: bool; 13 | input_linefeeds: bool; 14 | } 15 | 16 | tty_sane :: () { 17 | state := tty_get(); 18 | state.echo = true; 19 | state.input_buffered = true; 20 | tty_set(&state); 21 | } 22 | 23 | tty_raw :: () { 24 | state := tty_get(); 25 | state.echo = false; 26 | state.input_buffered = false; 27 | tty_set(&state); 28 | } 29 | 30 | #if runtime.platform.Supports_TTY { 31 | 32 | tty_get :: () -> TTY_State { 33 | state: TTY_State; 34 | runtime.platform.__tty_get(&state); 35 | return state; 36 | } 37 | 38 | tty_set :: (state: &TTY_State) -> bool { 39 | return runtime.platform.__tty_set(state); 40 | } 41 | 42 | } else { 43 | 44 | tty_get :: () -> TTY_State { 45 | assert(false, "core.os.tty_get not supported on this platform."); 46 | } 47 | 48 | tty_set :: (state: &TTY_State) -> bool { 49 | assert(false, "core.os.tty_get not supported on this platform."); 50 | return false; 51 | } 52 | 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /core/runtime/build_opts.onyx: -------------------------------------------------------------------------------- 1 | package runtime 2 | 3 | // runtime: Runtime This is set by the compiler 4 | Runtime :: enum { 5 | Onyx :: 1; 6 | Wasi :: 2; 7 | Js :: 3; 8 | Custom :: 4; 9 | } 10 | 11 | // compiler_os This is set by the compiler. It is not called 'os' because that conflicts with the 'core.os' package. 12 | OS :: enum { 13 | Linux :: 1; 14 | Windows :: 2; 15 | MacOS :: 3; 16 | } 17 | 18 | // arch: Arch This is set by the compiler. 19 | Arch :: enum { 20 | Unknown :: 0; 21 | X86_64 :: 1; 22 | X86_32 :: 2; 23 | AARCH64 :: 3; 24 | } 25 | -------------------------------------------------------------------------------- /core/runtime/default_link_options.onyx: -------------------------------------------------------------------------------- 1 | package runtime.vars 2 | 3 | #if !#defined(link_options) { 4 | link_options :: Link_Options.{} 5 | } 6 | -------------------------------------------------------------------------------- /core/runtime/info/foreign_blocks.onyx: -------------------------------------------------------------------------------- 1 | 2 | package runtime.info 3 | 4 | // 5 | // Foreign Blocks 6 | // Because foreign blocks can generate a lot of data, and their data is only 7 | // really helpful in a handful of cases, you need to pass "--generate-foreign-info" 8 | // to have these arrays filled out. 9 | // 10 | 11 | foreign_block :: #distinct u32 12 | 13 | foreign_blocks: [] &Foreign_Block; 14 | 15 | Foreign_Block :: struct { 16 | module_name: str; 17 | funcs: [] Foreign_Function; 18 | 19 | Foreign_Function :: struct { 20 | name: str; 21 | type: type_expr; 22 | tags: [] any; 23 | } 24 | } 25 | 26 | get_foreign_block :: (f: foreign_block) -> &Foreign_Block { 27 | if ~~f < cast(i32) 0 || ~~f >= cast(i32) foreign_blocks.count do return null; 28 | 29 | return foreign_blocks[cast(i32) f]; 30 | } 31 | -------------------------------------------------------------------------------- /core/runtime/info/global_tags.onyx: -------------------------------------------------------------------------------- 1 | package runtime.info 2 | 3 | use core {array, slice} 4 | 5 | tagged_globals: [] &Tagged_Global 6 | 7 | Tagged_Global :: struct { 8 | data: rawptr; 9 | type: type_expr; 10 | tags: [] any; 11 | pack: package_id; 12 | } 13 | 14 | #local GGWT_Result :: struct (T: type_expr) { 15 | data: rawptr; 16 | type: type_expr; 17 | tag: &T; 18 | pack: package_id; 19 | } 20 | 21 | get_globals_with_tag :: ($tag_type: type_expr) -> [] GGWT_Result(tag_type) { 22 | results := make([..] GGWT_Result(tag_type)); 23 | 24 | for glob in tagged_globals { 25 | slice.find_opt(glob.tags, [v](v.type == tag_type))->with([tag] { 26 | array.push(&results, .{ 27 | data = glob.data, 28 | type = glob.type, 29 | tag = cast(&tag_type) tag.data, 30 | pack = glob.pack, 31 | }); 32 | }); 33 | } 34 | 35 | return results; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /core/runtime/info/proc_tags.onyx: -------------------------------------------------------------------------------- 1 | 2 | package runtime.info 3 | 4 | use core.array 5 | 6 | tagged_procedures: [] &Tagged_Procedure 7 | 8 | Tagged_Procedure :: struct { 9 | // This should be cast to the correct function type. 10 | // i.e. *cast(&(i32, i32) -> i32) &tagged_procedures[0].func; 11 | func: () -> void; 12 | type: type_expr; 13 | tags: [] any; 14 | pack: package_id; 15 | } 16 | 17 | get_tags_for_procedure :: (func: $T) -> [] any { 18 | if get_type_info(T).kind != .Function do return .[]; 19 | 20 | for tagged_procedures { 21 | if (*cast(&T) &it.func) == func do return it.tags; 22 | } 23 | 24 | return .[]; 25 | } 26 | 27 | #local GPWT_Result :: struct (T: type_expr) { 28 | func: () -> void; 29 | type: type_expr; 30 | tag : &T; 31 | pack: package_id; 32 | } 33 | 34 | get_procedures_with_tag :: ($tag_type: type_expr) -> [] GPWT_Result(tag_type) { 35 | results := make([..] GPWT_Result(tag_type)); 36 | 37 | for proc in tagged_procedures { 38 | if tag := array.first(proc.tags, [v](v.type == tag_type)); tag != null { 39 | array.push(&results, .{ 40 | func = proc.func, 41 | type = proc.type, 42 | tag = cast(&tag_type) tag.data, 43 | pack = proc.pack, 44 | }); 45 | } 46 | } 47 | 48 | return results; 49 | } 50 | -------------------------------------------------------------------------------- /core/runtime/info/stack_trace.onyx: -------------------------------------------------------------------------------- 1 | package runtime.info 2 | 3 | use runtime 4 | use core {alloc} // These can included because this file is only included in non-custom runtimes. 5 | 6 | // 7 | // This file contains the code for working with runtime stack traces. 8 | // The only function in this file is `get_stack_trace`, which returns 9 | // an array of stack nodes, allocated from the threads temporary allocator. 10 | // This is not the `context.temp_allocator`, because certain builtin in 11 | // allocators use `get_stack_trace`, and can accidentally cause infinite 12 | // recursion. 13 | // 14 | 15 | Stack_Node :: struct { 16 | file: str; 17 | line: u32; 18 | func_name: str; 19 | func_type: type_expr; 20 | } 21 | 22 | Stack_Trace :: struct { 23 | prev: &Stack_Trace; 24 | data: &Stack_Node; 25 | current_line: u32; 26 | } 27 | 28 | Stack_Frame :: struct { 29 | info: &Stack_Node; 30 | current_line: u32; 31 | } 32 | 33 | #if runtime.Stack_Trace_Enabled { 34 | 35 | get_stack_trace :: () -> [..] Stack_Frame { 36 | trace := make([..] Stack_Frame, 8, alloc.temp_allocator); 37 | 38 | walker := __stack_trace.prev; 39 | while walker { 40 | trace << .{ walker.data, walker.current_line }; 41 | walker = walker.prev; 42 | } 43 | 44 | return trace; 45 | } 46 | 47 | } else { 48 | 49 | get_stack_trace :: () -> [] Stack_Frame { 50 | return .[]; 51 | } 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /core/runtime/platform/onyx/env.onyx: -------------------------------------------------------------------------------- 1 | package runtime.platform 2 | 3 | use core {Pair} 4 | 5 | __get_all_env :: () -> [] Pair(str, str) { 6 | // TODO 7 | return .[]; 8 | } 9 | 10 | __get_env :: (key: str) -> ? str { 11 | #persist buf: [512] u8; 12 | len := __lookup_env(key, buf); 13 | 14 | if len > 0 do return buf[0 .. len]; 15 | 16 | return .{}; 17 | } 18 | 19 | #local #foreign "onyx_runtime" { 20 | __lookup_env :: (key: str, buf: str) -> i32 --- 21 | } 22 | 23 | -------------------------------------------------------------------------------- /core/runtime/platform/wasi/wasi_env.onyx: -------------------------------------------------------------------------------- 1 | package runtime.platform 2 | 3 | use wasi { environ_get, environ_sizes_get, Size } 4 | use core {Pair, string, slice} 5 | 6 | #local { 7 | all_env: [] Pair(str, str); 8 | } 9 | 10 | #local 11 | __lookup_all_envs :: () { 12 | if all_env do return; 13 | 14 | allocator := context.allocator; 15 | 16 | env_count, env_buf_size : Size; 17 | environ_sizes_get(&env_count, &env_buf_size); 18 | 19 | env_var := make([] cstr, env_count, allocator); 20 | env_buf := make([] u8, env_buf_size, allocator); 21 | 22 | environ_get(env_var.data, env_buf.data); 23 | 24 | // Fix pointers to be only 4 bytes wide 25 | while i := cast(i32) (env_var.count - 1); i >= 0 { 26 | defer i -= 1; 27 | env_var[i] = cast(cstr) (cast([&]u32) env_var.data)[i]; 28 | } 29 | 30 | result := make([..] Pair(str, str), env_count, allocator); 31 | for env in env_var { 32 | s := string.from_cstr(env); 33 | var, val := string.bisect(s, '='); 34 | result << .{var, val}; 35 | } 36 | 37 | delete(&env_var, allocator); 38 | 39 | all_env = result; 40 | } 41 | 42 | __get_all_env :: () -> [] Pair(str, str) { 43 | __lookup_all_envs(); 44 | 45 | return all_env; 46 | } 47 | 48 | __get_env :: (key: str) -> ? str { 49 | __lookup_all_envs(); 50 | 51 | return slice.first(all_env, [v](v.first == key)) 52 | |> Optional.from_ptr() 53 | |> Optional.transform(x => x.second); 54 | } 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /core/string/char_utils.onyx: -------------------------------------------------------------------------------- 1 | package core.string 2 | 3 | #inject u8 { 4 | is_alpha :: (c: u8) -> bool { 5 | return (c >= #char "A" && c <= #char "Z") || 6 | (c >= #char "a" && c <= #char "z"); 7 | } 8 | 9 | is_num :: (c: u8) -> bool { 10 | return (c >= #char "0" && c <= #char "9"); 11 | } 12 | 13 | is_lower :: (c: u8) -> bool { 14 | return (c >= #char "a" && c <= #char "z"); 15 | } 16 | 17 | is_upper :: (c: u8) -> bool { 18 | return (c >= #char "A" && c <= #char "Z"); 19 | } 20 | 21 | is_alphanum :: (c: u8) -> bool { 22 | return c->is_alpha() || c->is_num(); 23 | } 24 | 25 | is_whitespace :: (c: u8) -> bool { 26 | return c == #char " " || c == #char "\n" || c == #char "\t" || c == #char "\v"; 27 | } 28 | 29 | to_upper :: (c: u8) -> u8 { 30 | if c >= 'a' && c <= 'z' do return c - 32; 31 | return c; 32 | } 33 | 34 | to_lower :: (c: u8) -> u8 { 35 | if c >= 'A' && c <= 'Z' do return c + 32; 36 | return c; 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /core/string/string_pool.onyx: -------------------------------------------------------------------------------- 1 | package core.string 2 | 3 | use core.alloc 4 | use core.alloc.arena 5 | use core.memory 6 | 7 | // 8 | // Many times, storing strings is annoying because you need 9 | // to keep the data alive, while moving pointers around and 10 | // changing them. 11 | // 12 | // To remedy this, a StringPool is a simple wrapper around 13 | // an arena allocator that enables you to quickly copy a 14 | // string to the pool. From there, you can use the string 15 | // until the pool is cleared or freed. 16 | // 17 | StringPool :: struct { 18 | arena: arena.Arena; 19 | } 20 | 21 | #inject StringPool { 22 | add :: pool_add; 23 | flush :: pool_flush; 24 | free :: pool_free; 25 | } 26 | 27 | // 28 | // Creates a StringPool capable of storing a string of at 29 | // most `maximum_string_length` bytes. 30 | pool_make :: (maximum_string_length := 16384, allocator := context.allocator) => 31 | StringPool.{ 32 | arena.make(allocator, maximum_string_length) 33 | } 34 | 35 | // 36 | // Copies a string into the pool, returning the copied string. 37 | pool_add :: (sp: &StringPool, s: str) -> str { 38 | if s.count > sp.arena.arena_size do return ""; 39 | 40 | allocator := alloc.as_allocator(&sp.arena); 41 | 42 | new_str := make(str, s.count, allocator); 43 | memory.copy(new_str.data, s.data, s.count); 44 | return new_str; 45 | } 46 | 47 | // 48 | // Clears all entries in the pool. 49 | pool_flush :: (sp: &StringPool) { 50 | arena.clear(&sp.arena); 51 | } 52 | 53 | // 54 | // Completely frees all memory in the pool. 55 | pool_free :: (sp: &StringPool) { 56 | arena.free(&sp.arena); 57 | } 58 | 59 | #overload 60 | builtin.delete :: pool_free 61 | 62 | -------------------------------------------------------------------------------- /core/sync/once.onyx: -------------------------------------------------------------------------------- 1 | package core.sync 2 | 3 | // 4 | // Once is a thread-safe mechanism for executing a particular 5 | // function only once. It is simply a flag with a mutex. 6 | // 7 | 8 | #doc "Represents something will only happen once." 9 | Once :: struct { 10 | done: bool; 11 | mutex: Mutex; 12 | } 13 | 14 | #inject Once.exec :: #match #local {} 15 | 16 | #doc "Run a function with no arguments once." 17 | #overload 18 | Once.exec :: (o: &Once, f: () -> $R) { 19 | scoped_mutex(&o.mutex); 20 | if o.done do return; 21 | 22 | o.done = true; 23 | f(); 24 | } 25 | 26 | #doc "Run a function with one argument once." 27 | #overload 28 | Once.exec :: (o: &Once, ctx: $Ctx, f: (Ctx) -> $R) { 29 | scoped_mutex(&o.mutex); 30 | if o.done do return; 31 | 32 | o.done = true; 33 | f(ctx); 34 | } 35 | -------------------------------------------------------------------------------- /docs/ideas/ditching_wasi.md: -------------------------------------------------------------------------------- 1 | Ditching WASI 2 | ------------- 3 | 4 | After programming with the dedicated Onyx Runtime and extensible C interop, 5 | I am beginning to hate WASI, as I see it as unnecessarily restrictive and all 6 | implementations of WASI lack 50% of the features that it claim. If they fully 7 | supported all features proposed by WASI, I may be more for it. But as it stands 8 | WASI is an incomplete mess that has seen no active development in years and I 9 | would like to ditch it for the Onyx Runtime. It will still remain available for 10 | the WASI runtime, obviously, but I want to completely ditch it elsewhere. 11 | 12 | In addition to reimplementing the file, directory and clock operations that were 13 | available in WASI, Onyx could support a proper TCP/UDP networking protocol, 14 | probabily similar to the socket library in Python. 15 | 16 | Good article about differences between Winsock and Berkeley sockets: 17 | https://handsonnetworkprogramming.com/articles/differences-windows-winsock-linux-unix-bsd-sockets-compatibility/ 18 | 19 | One small technicality that has to be resolved is command line arguments without 20 | WASI. I think just setting global data and then the Onyx `_startup` function will 21 | envoke specific function like is done in WASI. 22 | 23 | -------------------------------------------------------------------------------- /docs/ideas/doc_format.md: -------------------------------------------------------------------------------- 1 | Documentation file format 2 | ========================= 3 | 4 | Capturing the follow: 5 | - Package Hierarchy 6 | - Type info 7 | - Public symbols 8 | - Private symbols 9 | - Procedures 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/ideas/high_level_goals.md: -------------------------------------------------------------------------------- 1 | High-Level Goals 2 | ================ 3 | 4 | There are many ideas that are wizzing around my head 5 | when I think about the future of Onyx, and I'm having 6 | a hard-time deciding what needs to be done and when. 7 | I think writing everything out and creating a (rough) 8 | timeline will be beneficial to me and the future of 9 | the language. 10 | 11 | 12 | Optimizing OVM instructions 13 | --------------------------- 14 | As OVM becomes used more and more because of its improved 15 | debugging experience when compared to runtimes like Wasmer, 16 | it would be nice if the runtime was a little faster. As 17 | I look through the generated instructions, I see a lot of 18 | potential for some relatively easy improvements that can 19 | be made. This would still be a larger-endeavour, as 20 | optimizing is not a simple task. Debug information, basic 21 | blocks and other tricky things have to be dealt with. I 22 | think this task would take around 2-3 weeks of focused time 23 | to get something good. 24 | 25 | [Onyx Website](./website.md) 26 | -------------- 27 | The domains for the website (https://onyxlang.io) is already 28 | registered, I just need a good-enough website. It does not 29 | need to be anything super-fancy, yet. Just links and basic- 30 | documentation. 31 | 32 | 33 | [Generated Documentation](./doc_format.md) 34 | ----------------------- 35 | 36 | 37 | [Core Library Cleanup](./core_libraries.md) 38 | - [ ] Add improved time functionality 39 | - [ ] clock_gettime 40 | - [ ] clock_settime 41 | - [ ] clock_getres 42 | - [ ] clock 43 | -------------------- 44 | 45 | 46 | [Project Templates](./templated_projects.md) 47 | ------------------ 48 | 49 | 50 | [Bundling Onyx for Distribution](./shipping.md) 51 | ------------------------------- 52 | 53 | -------------------------------------------------------------------------------- /docs/ideas/mapped_directories.md: -------------------------------------------------------------------------------- 1 | Mapped Directories 2 | ================== 3 | 4 | I am thinking about complicating how the file resolution 5 | system works when loading new files. Currently, it is 6 | intentionally very simple. There is a global "search path" 7 | that will be sequentially appended to the file path being 8 | loaded, and the first full path that is a file will be used. 9 | This makes it easy to use, but also causes some confusion. 10 | 11 | I think it would be worth investigating using a *relative only* 12 | scheme for file resolution, UNLESS you specify the full path, 13 | or a *mapped directory* to use as the base directory. 14 | 15 | For example, instead of relying on "/usr/share/onyx" to be in 16 | the search path to make "core/module" work, we would instead have 17 | "core" be a mapped directory to "/usr/share/onyx/core". Then, 18 | you would say, `#load "core:module"` or `#load core "module"` to 19 | specify the base path. 20 | -------------------------------------------------------------------------------- /docs/ideas/module_thoughts: -------------------------------------------------------------------------------- 1 | Modules in Onyx 2 | --------------- 3 | 4 | Modules are going to be the form of reusable code in Onyx. They should be a 5 | self-contained (maybe dependent on other modules), collection of Onyx files 6 | with a module.onyx in the root folder that loads all relevant files to the 7 | module. Modules can then easily be included by loading the module.onyx file 8 | of any module. 9 | 10 | Things that need to be decided about modules: 11 | - How should modules be searched for in the filesystem? 12 | - How should javascript code in modules be easily maintained? 13 | Current solutions just copy the relevant javascript on build. 14 | 15 | Things that need to be done in the compiler: 16 | - Rename 'package' to 'namespace' 17 | I think 'namespace' better reflects the way I think about 'packages'. 18 | I don't want it to feel too 'C++-y' but I think the nomenclature change is worthwhile. 19 | 20 | 'package' was orginally inspired by Java, but there the folder structure must match 21 | the package structure. In Onyx, that is not the case because it allows for packages 22 | to be extended on without needing to modify the source of the original package. 23 | 24 | - Add relative file loads and relative #file_contents. 25 | If the string starts with './', it should be considered relative. 26 | This will make it easier for modules to include their files, regardless of 27 | how the project is set up. 28 | 29 | ✔ This has been done 30 | -------------------------------------------------------------------------------- /docs/ideas/multi-pointers.md: -------------------------------------------------------------------------------- 1 | Multi-Pointers 2 | ============== 3 | 4 | &T - Pointer to a single T 5 | [5] T - Array of 5 T's 6 | [] T - Slice of T (pointer to initial element, and a count) 7 | [..] T - Dynamic array of T (pointer to initial element, count, capacity and allocator) 8 | [&] T - Pointer to many T's 9 | 10 | This proposal would eliminate the usage of `t[x]` and `t + i` for a `t` of type `&T`. Instead, 11 | `t` would have to be of type `[&] T` to do this. Multi-pointers would affectively 12 | be exactly like normal pointers, but would have this ability. 13 | 14 | I think the easiest way to implement them is by having a flag on TypePointer. 15 | Then modify the checker to allow for the `t[x]` and `t + i` syntax. 16 | 17 | Also, slices and dynamic arrays would have to have their internal data pointer types 18 | become `[&] T`, so the can actually be used like arrays. 19 | 20 | As for updating existing code, I don't think there would be too much to update. The 21 | largest hurdle will be the code that works with `any` types, as it is common there to 22 | cast to a `&u8` and use pointer addition. There should be/already is a better substitute 23 | for this, but making this change would break all of that code. By my estimate, I think 24 | that would comprise: 25 | - `core.misc`'s any library 26 | - `json` library 27 | -------------------------------------------------------------------------------- /docs/ideas/shipping.md: -------------------------------------------------------------------------------- 1 | This file discusses what Onyx will look like in its shipped form, on Windows, MacOS and Linux. 2 | 3 | Windows 4 | --------------------- 5 | Things that are needed: 6 | * onyx.exe exists in the path 7 | * onyx.exe knows where the core modules are installed (%APPDATA%\Local ?) 8 | 9 | MacOS 10 | --------------------- 11 | I know nothing about shipping portable things on MacOS... 12 | 13 | Linux 14 | --------------------- 15 | The way that build.sh installs Onyx on Linux is pretty close to the long term solution. That being, 16 | copying the core library to /usr/share/onyx/core and the necessary dependencies (libwasmer at the 17 | moment) to /usr/share/onyx/lib, and the executable to /usr/bin/onyx. This feels pretty intact with 18 | how most things are shipped on Linux. The only change I would have would be to copy things to 19 | /usr/local/... instead of /usr/... just to avoid possible conflicts. 20 | 21 | -------------------------------------------------------------------------------- /docs/ideas/tagged_unions.md: -------------------------------------------------------------------------------- 1 | Tagged Unions 2 | ------------- 3 | 4 | Declaring a union of two types. 5 | 6 | Error :: union { 7 | io: struct { ... }; 8 | network: struct { ... }; 9 | } 10 | 11 | Creating a value of that union. 12 | Struct literal must have EXACTLY ONE NAMED member. 13 | 14 | err := Error.{ io = .{ ... } }; 15 | 16 | Accessing data. 17 | 18 | switch err { 19 | case .io => io_error { 20 | // use io_error 21 | } 22 | 23 | case .network => network_error { 24 | // use network_error 25 | } 26 | } 27 | 28 | Fields. 29 | 30 | Error.tag_enum // Implicit enum created for every union. would be enum {io, network} 31 | 32 | Error.tag_enum.io // Enum value 33 | 34 | err.io // Same as Error.tag_enum.io 35 | 36 | cast(Error.tag_enum) err // Get the tagged value out of the union 37 | 38 | -------------------------------------------------------------------------------- /docs/ideas/templated_projects.md: -------------------------------------------------------------------------------- 1 | Templated Projects 2 | ================== 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/logos/logo-new-256.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo-new-256.ico -------------------------------------------------------------------------------- /docs/logos/logo-new-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo-new-256.png -------------------------------------------------------------------------------- /docs/logos/logo-new-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo-new-32.png -------------------------------------------------------------------------------- /docs/logos/logo-new-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo-new-512.png -------------------------------------------------------------------------------- /docs/logos/logo-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo-new.png -------------------------------------------------------------------------------- /docs/logos/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo.ico -------------------------------------------------------------------------------- /docs/logos/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo.png -------------------------------------------------------------------------------- /docs/logos/logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo_256.png -------------------------------------------------------------------------------- /docs/logos/logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/docs/logos/logo_512.png -------------------------------------------------------------------------------- /examples/02_variables.onyx: -------------------------------------------------------------------------------- 1 | // Notice this time, we are not adding, 'package main' or '#load "core/module"' 2 | // to the top of the file, since every file is automatically part of the 3 | // main package unless specified otherwise, and every compilations includes 4 | // the standard library. 5 | 6 | use core 7 | 8 | main :: () { 9 | 10 | // To declare a local variable, the variable name is simply followed by 11 | // a single ':', and then the type of the variable is given. In this case, 12 | // `foo` is an `i32`, which is Onyx's 32-bit signed integer type. It is 13 | // then immediately assigned the value of 10. 14 | foo: i32; 15 | foo = 10; 16 | 17 | // You can combine the two lines above into one, just as you would expected. 18 | // This declares `bar` to be an `i32`, and assigns it the value 10. 19 | bar: i32 = 10; 20 | 21 | // As a MAJOR convenience, you can omit the type of a variable, if it can 22 | // be determined by the type of the right hand side expression. In this 23 | // line, the integer `15` defaults to the type `i32`. This type is then 24 | // used as the type of `qux`. This may not seem super useful yet, but 25 | // when there are very compilated types in your program, this saves 26 | // a lot of typing and _arguably_ makes the code more readable. 27 | qux := 15; 28 | 29 | // 30 | // As an aside, the `printf` function in the `core` package is used to 31 | // print formatted strings. Because of a lot of language features that 32 | // will be discussed later, `printf` simply uses '{}' to denote where 33 | // a value should be formatted, instead of pre-typed strings, like "%s", 34 | // or "%d" from C. 35 | core.printf("foo is {}\n", foo); 36 | core.printf("bar is {}\n", bar); 37 | core.printf("qux is {}\n", qux); 38 | } 39 | -------------------------------------------------------------------------------- /examples/05_slices.onyx: -------------------------------------------------------------------------------- 1 | // Slices are a useful and simple data structure that are commonly 2 | // used throughout almost all Onyx programs. A slice in Onyx simply 3 | // represents a two member structure, consisting of a pointer, and 4 | // an unsigned count. Although that sounds deceptively simple, it 5 | // is a powerful construct to have. In fact, strings in Onyx, i.e. 6 | // the 'str' type, is actually just a slice of u8. 7 | 8 | #load "core/module" 9 | 10 | use core {*} 11 | 12 | main :: (args: [] cstr) { 13 | // A dummy array to demonstrate. 14 | arr := i32.[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ]; 15 | 16 | // In Onyx a slice type is simply written as an empty pair of 17 | // square brackets, with the type of elements of the slice 18 | // immediately following. 19 | slice : [] i32; 20 | 21 | // Slices have two members, data and count. You can set them directly. 22 | slice.data = ^arr[3]; 23 | slice.count = 4; 24 | 25 | // You can iterate over slices directly using a for-loop. 26 | for elem in slice do printf("{} ", elem); 27 | print("\n"); 28 | 29 | // Another equivalent way of writing lines 22 and 23 is to 30 | // use the array subscript notation, but provide a range for 31 | // the index as so. This is generally called the slice literal 32 | // notation. 33 | slice = arr[3 .. 7]; 34 | 35 | // Printing it out to verify it is the same. 36 | for elem in slice do printf("{} ", elem); 37 | print("\n"); 38 | 39 | // Since strings are represented as slices in Onyx, substrings 40 | // are easily accessed using the same slice literal syntax. 41 | some_string := "This is a test string for demoing purposes."; 42 | substr := some_string.data[10 .. 14]; 43 | println(substr); 44 | } 45 | -------------------------------------------------------------------------------- /examples/16_pipe_operator.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core { println } 4 | 5 | main :: (args: [] cstr) { 6 | // These functions will be used to demo the pipe operator. 7 | Num :: #type i32; 8 | double :: (v: Num) -> Num do return v * 2; 9 | add :: (a: Num, b: Num) -> Num do return a + b; 10 | square :: (v: Num) -> Num do return v * v; 11 | 12 | // Something you may find yourself doing often is changing function 13 | // calls together likes this: 14 | println(square(add(double(4), 3))); 15 | 16 | // I think we can agree that that line is hard to understand just 17 | // by looking at it. This kind of pattern appears very often, at 18 | // least in the way that I program, so I wanted to have a way to 19 | // make this kind of operation cleaner. My solution was the pipe 20 | // operator (|>). The above code can be rewritten as so: 21 | double(4) |> add(3) |> square() |> println(); 22 | 23 | // The pipe operator simply places the expression on its left into 24 | // the FIRST argument slot of the function call on its right. The 25 | // operator is left associative, so the implicit parentheses are 26 | // exactly where you expect them to be. For example, 27 | // a |> f(b, c) |> g(d) 28 | // is the same as, 29 | // (a |> f(b, c)) |> g(d) 30 | // which becomes, 31 | // g(f(a, b, c), d) 32 | // 33 | // This may seem a little simple and useless, and that is okay. 34 | // It is not an operator you probably will not have to use very 35 | // often; But when you have code like the first println above, 36 | // it can clean up the code and make it easier to read. 37 | } 38 | -------------------------------------------------------------------------------- /examples/17_operator_overload.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | use core {*} 3 | 4 | // Operator overloading allows you to define what it means to perform 5 | // a binary operation between two types. In Onyx, they are defined in 6 | // the following way: 7 | // 8 | // #operator 9 | // 10 | // where is the binary operator, and is an expression 11 | // that should be a procedure that will be used for the overload. 12 | // 13 | 14 | // Take this example. Note, DO NOT actually use this exact implementation 15 | // because it leaks memory all over the place. Especially because with 16 | // a binary operator, you cannot pass a custom allocator. 17 | 18 | #operator + (x: str, y: str) -> str { 19 | return string.concat(x, y); 20 | } 21 | 22 | main :: (args: [] cstr) { 23 | // Now we can say "+" between two strings. Also, we can use it 24 | // to give us access to more features like array.sum which adds 25 | // everything in the array together using the '+' operator. 26 | // Since '+' is concatenate, array.sum will join all the strings 27 | // into one, in one of the most inefficient ways possible. 28 | 29 | test := "Hello, " + "World!"; 30 | println(test); 31 | 32 | strings := str.[ "This ", "is ", "a ", "test." ]; 33 | result := array.sum(cast([] str) strings, start=""); 34 | println(result); 35 | 36 | // As a side note, '==' is already overloaded for strings in the 37 | // standard library, so you can do this: 38 | 39 | if array.contains(cast([] str) strings, "is ") { 40 | println("The array contains 'is '."); 41 | } else { 42 | println("The array does NOT contain 'is '."); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/20_auto_return.onyx: -------------------------------------------------------------------------------- 1 | // Sometimes it can be a lot to explicitly write out the 2 | // return type of a function. In fact, there are times in 3 | // Onyx where it is actually impossible to write the return 4 | // type of a function, as you'll see later. 5 | 6 | main :: (args: [] cstr) { 7 | // If you don't want to explicitly write the return type 8 | // of a function, you can use #auto: 9 | f :: (x: i32) -> #auto { 10 | return x * 2; 11 | } 12 | 13 | y := f(10); 14 | printf("Y({}): {}\n", typeof y, y); 15 | 16 | // That's really all you need to know... It is just a 17 | // convinent shorthand. However, like I said, there are 18 | // some cases where it is impossible to actually write 19 | // the type so #auto is the only solution. Take this 20 | // example. It takes something that is iterable, and 21 | // returns an array of whatever that iterable iterates 22 | // over. Because the only way to pattern match the V 23 | // variable is by using it as a parameter, there is an 24 | // inner macro that serves that purpose. It would be 25 | // impossible to write the return type of consume, because 26 | // it would be "[] V", but where would the V variable 27 | // come from? The only way to do this is use an auto-return 28 | // type and let the compiler fill it in. 29 | 30 | consume :: (it: $T) -> #auto where iter.Iterable(T) { 31 | consume_inner :: macro (it: Iterator($V)) -> [] V { 32 | arr: [..] V; 33 | for v in it do arr << v; 34 | return arr; 35 | } 36 | 37 | return consume_inner(iter.as_iter(it)); 38 | } 39 | 40 | 41 | arr := consume(range.{ 10, 1, -1 }); 42 | println(arr); 43 | } 44 | 45 | #load "core/module" 46 | use core {*} 47 | 48 | -------------------------------------------------------------------------------- /interpreter/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # FLAGS="-g3 -O2 -DOVM_DEBUG=1 -fno-stack-protector" 4 | # FLAGS="-g3 -DOVM_VERBOSE=1" 5 | FLAGS="-O3 -fno-stack-protector" 6 | LIBS="-pthread" 7 | TARGET="../shared/lib/$ONYX_ARCH/lib/libovmwasm.a" 8 | C_FILES="src/ovmwasm.c src/vm/*.c src/wasm/*.c src/debug/*.c" 9 | INCLUDES="-I../shared/include -Iinclude" 10 | 11 | if [ ! -z ${ONYX_TARGET+x} ]; then 12 | FLAGS="$FLAGS --target=$ONYX_TARGET" 13 | fi 14 | 15 | mkdir -p "build_tmp" 16 | 17 | echo "Compiling ovmwasm to $TARGET" 18 | for c_file in $C_FILES; do 19 | $ONYX_CC $FLAGS $INCLUDES -fPIC -o build_tmp/$(basename $c_file).o -c $c_file $LIBS 20 | done 21 | 22 | ar crs "$TARGET" build_tmp/*.o* 23 | 24 | rm -r "build_tmp" 25 | -------------------------------------------------------------------------------- /interpreter/src/ovmwasm.c: -------------------------------------------------------------------------------- 1 | #define BH_DEFINE 2 | #define BH_NO_TABLE 3 | #define BH_INTERNAL 4 | #define STB_DS_IMPLEMENTATION 5 | #include "bh.h" 6 | #include "stb_ds.h" 7 | 8 | #include "ovm_wasm.h" 9 | -------------------------------------------------------------------------------- /interpreter/src/wasm/config.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | 4 | wasm_config_t *wasm_config_new() { 5 | wasm_config_t *config = malloc(sizeof(*config)); 6 | config->debug_enabled = false; 7 | config->listen_path = "/tmp/ovm-debug.0000"; 8 | return config; 9 | } 10 | 11 | void wasm_config_delete(wasm_config_t *config) { 12 | free(config); 13 | } 14 | 15 | void wasm_config_enable_debug(wasm_config_t *config, bool enabled) { 16 | config->debug_enabled = enabled; 17 | } 18 | 19 | void wasm_config_set_listen_path(wasm_config_t *config, char *listen_path) { 20 | config->listen_path = listen_path; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /interpreter/src/wasm/engine.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_engine_t *wasm_engine_new() { 6 | wasm_engine_t *engine = wasm_engine_new_with_config(NULL); 7 | return engine; 8 | } 9 | 10 | wasm_engine_t *wasm_engine_new_with_config(wasm_config_t *config) { 11 | ovm_store_t *store = ovm_store_new(); 12 | 13 | wasm_engine_t *engine = bh_alloc_item(store->heap_allocator, wasm_engine_t); 14 | engine->config = config; 15 | engine->store = store; 16 | 17 | ovm_engine_t *ovm_engine = ovm_engine_new(store); 18 | engine->engine = ovm_engine; 19 | 20 | if (config && config->debug_enabled) { 21 | // This should maybe be moved elsewhere? 22 | debug_state_t *debug = bh_alloc_item(store->heap_allocator, debug_state_t); 23 | ovm_engine_enable_debug(engine->engine, debug); 24 | 25 | debug_host_init(engine->engine->debug, engine->engine); 26 | debug->listen_path = config->listen_path; 27 | 28 | debug_host_start(engine->engine->debug); 29 | } 30 | 31 | return engine; 32 | } 33 | 34 | void wasm_engine_delete(wasm_engine_t *engine) { 35 | if (engine->engine->debug) { 36 | debug_host_stop(engine->engine->debug); 37 | } 38 | 39 | ovm_store_t *store = engine->store; 40 | ovm_engine_delete(engine->engine); 41 | bh_free(store->heap_allocator, engine); 42 | ovm_store_delete(store); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /interpreter/src/wasm/frame.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | 4 | 5 | void wasm_frame_delete(wasm_frame_t *frame) { 6 | // Don't have to free the frame because it was allocated on the 7 | // arena allocator. 8 | } 9 | 10 | WASM_DECLARE_VEC_IMPL(frame, *) 11 | 12 | wasm_frame_t *wasm_frame_copy(const wasm_frame_t* frame) { 13 | if (!frame) return NULL; 14 | assert(frame->instance); 15 | 16 | wasm_frame_t *new_frame = bh_alloc_item(frame->instance->store->engine->store->arena_allocator, wasm_frame_t); 17 | memcpy(new_frame, frame, sizeof(*frame)); 18 | 19 | return new_frame; 20 | } 21 | 22 | wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { 23 | return frame->instance; 24 | } 25 | 26 | u32 wasm_frame_func_index(const wasm_frame_t *frame) { 27 | return frame->func_idx; 28 | } 29 | 30 | size_t wasm_frame_func_offset(const wasm_frame_t *frame) { 31 | return frame->func_offset; 32 | } 33 | 34 | size_t wasm_frame_module_offset(const wasm_frame_t *frame) { 35 | return frame->module_offset; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /interpreter/src/wasm/global.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_global_t *wasm_global_new(wasm_store_t *store, const wasm_globaltype_t *type, const wasm_val_t *initial) { 6 | wasm_global_t *global = bh_alloc(store->engine->store->arena_allocator, sizeof(*global)); 7 | global->inner.type = wasm_globaltype_as_externtype_const(type); 8 | global->inner.global.register_index = -1; 9 | global->inner.global.engine = NULL; 10 | 11 | if (initial) { 12 | global->inner.global.initial_value = *initial; 13 | } 14 | 15 | return global; 16 | } 17 | 18 | wasm_globaltype_t *wasm_global_type(const wasm_global_t *global) { 19 | return (wasm_globaltype_t *) global->inner.global.type; 20 | } 21 | 22 | void wasm_global_get(const wasm_global_t *global, wasm_val_t *value) { 23 | assert(0 && "unimplemented"); 24 | } 25 | 26 | void wasm_global_set(wasm_global_t *global, const wasm_val_t *value) { 27 | assert(0 && "unimplemented"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /interpreter/src/wasm/memory.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_memory_t *wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) { 6 | wasm_memory_t *memory = bh_alloc(store->engine->store->arena_allocator, sizeof(*store)); 7 | memory->inner.type = wasm_memorytype_as_externtype_const(type); 8 | memory->inner.memory.type = type; 9 | memory->inner.memory.engine = NULL; 10 | 11 | return memory; 12 | } 13 | 14 | wasm_memorytype_t *wasm_memory_type(const wasm_memory_t *memory) { 15 | return (wasm_memorytype_t *) memory->inner.memory.type; 16 | } 17 | 18 | byte_t *wasm_memory_data(wasm_memory_t *memory) { 19 | assert(memory && memory->inner.memory.engine); 20 | return memory->inner.memory.engine->memory; 21 | } 22 | 23 | size_t wasm_memory_data_size(const wasm_memory_t *memory) { 24 | assert(memory && memory->inner.memory.engine); 25 | return memory->inner.memory.engine->memory_size; 26 | } 27 | 28 | wasm_memory_pages_t wasm_memory_size(const wasm_memory_t *memory) { 29 | assert(memory && memory->inner.memory.engine); 30 | return memory->inner.memory.engine->memory_size / MEMORY_PAGE_SIZE; 31 | } 32 | 33 | bool wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t pages) { 34 | return ovm_engine_memory_ensure_capacity(memory->inner.memory.engine, pages * MEMORY_PAGE_SIZE); 35 | } 36 | -------------------------------------------------------------------------------- /interpreter/src/wasm/ref.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_func_t *wasm_ref_as_func(wasm_ref_t *ref) { 6 | if (ref->stored_obj == wasm_ref_stored_obj_func) { 7 | return ref->func; 8 | } 9 | 10 | return NULL; 11 | } 12 | 13 | const wasm_func_t *wasm_ref_as_func_const(const wasm_ref_t *ref) { 14 | if (ref->stored_obj == wasm_ref_stored_obj_func) { 15 | return (const wasm_func_t *) ref->func; 16 | } 17 | 18 | return NULL; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /interpreter/src/wasm/store.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_store_t *wasm_store_new(wasm_engine_t *engine) { 6 | wasm_store_t *store = bh_alloc(engine->store->arena_allocator, sizeof(wasm_store_t)); 7 | store->engine = engine; 8 | store->instance = NULL; 9 | return store; 10 | } 11 | 12 | void wasm_store_delete(wasm_store_t *store) { 13 | } 14 | 15 | -------------------------------------------------------------------------------- /interpreter/src/wasm/table.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_table_t *wasm_table_new(wasm_store_t *store, const wasm_tabletype_t *type, wasm_ref_t *init) { 6 | wasm_table_t *table = bh_alloc(store->engine->store->arena_allocator, sizeof(*table)); 7 | table->inner.type = wasm_tabletype_as_externtype_const(type); 8 | table->inner.table.type = type; 9 | 10 | return table; 11 | } 12 | 13 | wasm_tabletype_t *wasm_table_type(const wasm_table_t *table) { 14 | return (wasm_tabletype_t *) table->inner.table.type; 15 | } 16 | 17 | wasm_ref_t *wasm_table_get(const wasm_table_t *table, unsigned int index) { 18 | const struct wasm_table_inner_t *tab = &table->inner.table; 19 | ovm_program_t *program = tab->program; 20 | ovm_engine_t *engine = tab->engine; 21 | 22 | // TODO bounds checking 23 | wasm_func_t *func = tab->instance->funcs[ 24 | program->static_integers[program->static_data[tab->static_arr].start_idx + index] 25 | ]; 26 | 27 | wasm_ref_t *new_ref = bh_alloc(engine->store->arena_allocator, sizeof(*new_ref)); 28 | new_ref->stored_obj = wasm_ref_stored_obj_func; 29 | new_ref->func = func; 30 | 31 | return new_ref; 32 | } -------------------------------------------------------------------------------- /interpreter/src/wasm/trap.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | #include "vm.h" 4 | 5 | wasm_trap_t *wasm_trap_new(wasm_store_t *store, const wasm_message_t *msg) { 6 | wasm_trap_t *trap = bh_alloc(store->engine->store->arena_allocator, sizeof(*trap)); 7 | trap->store = store; 8 | trap->msg = *msg; 9 | 10 | // 11 | // Generate frames 12 | bh_arr(ovm_stack_frame_t) ovm_frames = store->instance->state->stack_frames; 13 | int frame_count = bh_arr_length(ovm_frames); 14 | 15 | wasm_frame_vec_new_uninitialized(&trap->frames, frame_count); 16 | 17 | fori (i, 0, frame_count) { 18 | ovm_stack_frame_t *ovm_frame = &ovm_frames[frame_count - 1 - i]; 19 | wasm_frame_t *frame = bh_alloc(store->engine->store->arena_allocator, sizeof(*frame)); 20 | frame->instance = store->instance; 21 | frame->func_idx = ovm_frame->func->id; 22 | frame->func_offset = 0; 23 | frame->module_offset = 0; 24 | 25 | trap->frames.data[i] = frame; 26 | } 27 | 28 | return trap; 29 | } 30 | 31 | void wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) { 32 | *out = trap->msg; 33 | } 34 | 35 | wasm_frame_t *wasm_trap_origin(const wasm_trap_t *trap) { 36 | return trap->frames.data[0]; 37 | } 38 | 39 | void wasm_trap_trace(const wasm_trap_t *trap, wasm_frame_vec_t *frames) { 40 | frames->size = trap->frames.size; 41 | frames->data = trap->frames.data; 42 | } 43 | -------------------------------------------------------------------------------- /interpreter/src/wasm/value.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ovm_wasm.h" 3 | 4 | void wasm_val_delete(wasm_val_t* v) { 5 | // Apparently this is suppose to do nothing... 6 | } 7 | 8 | void wasm_val_copy(wasm_val_t* out, const wasm_val_t* in) { 9 | out->kind = in->kind; 10 | switch (out->kind) { 11 | case WASM_I32: out->of.i32 = in->of.i32; break; 12 | case WASM_I64: out->of.i64 = in->of.i64; break; 13 | case WASM_F32: out->of.f32 = in->of.i32; break; 14 | case WASM_F64: out->of.f64 = in->of.f64; break; 15 | case WASM_ANYREF: 16 | case WASM_FUNCREF: 17 | out->of.ref = in->of.ref; 18 | break; 19 | } 20 | } 21 | 22 | WASM_DECLARE_VEC_IMPL(val, ) 23 | 24 | 25 | -------------------------------------------------------------------------------- /misc/cloc_onyx_def: -------------------------------------------------------------------------------- 1 | Onyx 2 | filter remove_inline //.*$ 3 | filter call_regexp_common C++ 4 | extension onyx 5 | 3rd_gen_scale 2.30 6 | -------------------------------------------------------------------------------- /misc/icon_resource.rc: -------------------------------------------------------------------------------- 1 | desk1 ICON "docs/logos/logo.ico" -------------------------------------------------------------------------------- /misc/onyx-linux.sublime-build: -------------------------------------------------------------------------------- 1 | { 2 | "target": "exec", 3 | "shell_cmd": "/usr/bin/onyx -V --no-colors -o \"${folder}/${file_base_name}.wasm\" \"$file\"", 4 | "working_dir": "${folder}", 5 | "selector": "source.onyx", 6 | "file_regex": "^\\(([^:]+):([0-9]+),([0-9]+)\\) (.*)", 7 | } -------------------------------------------------------------------------------- /misc/onyx-windows.sublime-build: -------------------------------------------------------------------------------- 1 | { 2 | "target": "exec", 3 | "shell_cmd": "\\dev\\onyx\\onyx.exe -V -o \"${folder}\\\\${file_base_name}.wasm\" \"$file\"", 4 | "working_dir": "${folder}", 5 | "selector": "source.onyx", 6 | "file_regex": "^\\(([^:]+:[^:]+):([0-9]+),([0-9]+)\\) (.*)", 7 | } -------------------------------------------------------------------------------- /misc/onyx.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Comments 7 | scope 8 | source.onyx 9 | settings 10 | 11 | shellVariables 12 | 13 | 14 | name 15 | TM_COMMENT_START 16 | value 17 | // 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /misc/onyx_compiler.vim: -------------------------------------------------------------------------------- 1 | " Vim compiler file 2 | " Compiler: Onyx 3 | " Previous Maintainer: Brendan Hansen 4 | " Latest Revision: 2020-08-29 5 | 6 | if exists("current_compiler") 7 | finish 8 | endif 9 | let current_compiler = "onyx" 10 | 11 | let s:cpo_save = &cpo 12 | set cpo&vim 13 | 14 | CompilerSet errorformat=%E\(%f\:%l\\,%c\)\ \%m,%C%.%# 15 | 16 | set makeprg=onyx\ % 17 | 18 | let &cpo = s:cpo_save 19 | unlet s:cpo_save 20 | -------------------------------------------------------------------------------- /misc/vscode/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, Brendan Hansen 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /misc/vscode/debugAdapter.ts: -------------------------------------------------------------------------------- 1 | // Part of this code was taken from the example vscode debugger found here, 2 | // https://github.com/microsoft/vscode-mock-debug/blob/5524e7a3dd9ec176a987ffe3aebd489f1f543799/src/debugAdapter.ts` 3 | 4 | import { OVMDebugSession } from './ovmDebug'; 5 | 6 | import * as Net from 'node:net'; 7 | /* 8 | * When the debug adapter is run as an external process, 9 | * normally the helper function DebugSession.run(...) takes care of everything: 10 | * 11 | * MockDebugSession.run(MockDebugSession); 12 | * 13 | * but here the helper is not flexible enough to deal with a debug session constructors with a parameter. 14 | * So for now we copied and modified the helper: 15 | */ 16 | 17 | // first parse command line arguments to see whether the debug adapter should run as a server 18 | let port = 0; 19 | const args = process.argv.slice(2); 20 | args.forEach(function (val, index, array) { 21 | const portMatch = /^--server=(\d{4,5})$/.exec(val); 22 | if (portMatch) { 23 | port = parseInt(portMatch[1], 10); 24 | } 25 | }); 26 | 27 | if (port > 0) { 28 | Net.createServer((socket) => { 29 | const session = new OVMDebugSession(); 30 | session.setRunAsServer(true); 31 | session.start(socket, socket); 32 | }).listen(port); 33 | 34 | } else { 35 | 36 | // start a single session that communicates via stdin/stdout 37 | const session = new OVMDebugSession(); 38 | process.on('SIGTERM', () => { 39 | session.shutdown(); 40 | }); 41 | session.start(process.stdin, process.stdout); 42 | } -------------------------------------------------------------------------------- /misc/vscode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | ["{", "}"], 17 | ["[", "]"], 18 | ["(", ")"], 19 | ["\"", "\""] 20 | ], 21 | // symbols that that can be used to surround a selection 22 | "surroundingPairs": [ 23 | ["{", "}"], 24 | ["[", "]"], 25 | ["(", ")"], 26 | ["\"", "\""] 27 | ], 28 | "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)" 29 | } -------------------------------------------------------------------------------- /misc/vscode/logo-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/logo-icon.png -------------------------------------------------------------------------------- /misc/vscode/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/logo.png -------------------------------------------------------------------------------- /misc/vscode/onyx-0.0.4.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.0.4.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.0.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.1.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.1.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.2.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.2.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.3.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.3.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.4.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.4.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.5.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.5.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.6.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.6.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.7.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.7.vsix -------------------------------------------------------------------------------- /misc/vscode/onyx-0.1.8.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyx-0.1.8.vsix -------------------------------------------------------------------------------- /misc/vscode/onyxlang-0.1.10.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyxlang-0.1.10.vsix -------------------------------------------------------------------------------- /misc/vscode/onyxlang-0.1.9.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/misc/vscode/onyxlang-0.1.9.vsix -------------------------------------------------------------------------------- /misc/vscode/out/debugAdapter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Part of this code was taken from the example vscode debugger found here, 3 | // https://github.com/microsoft/vscode-mock-debug/blob/5524e7a3dd9ec176a987ffe3aebd489f1f543799/src/debugAdapter.ts` 4 | Object.defineProperty(exports, "__esModule", { value: true }); 5 | const ovmDebug_1 = require("./ovmDebug"); 6 | const Net = require("node:net"); 7 | /* 8 | * When the debug adapter is run as an external process, 9 | * normally the helper function DebugSession.run(...) takes care of everything: 10 | * 11 | * MockDebugSession.run(MockDebugSession); 12 | * 13 | * but here the helper is not flexible enough to deal with a debug session constructors with a parameter. 14 | * So for now we copied and modified the helper: 15 | */ 16 | // first parse command line arguments to see whether the debug adapter should run as a server 17 | let port = 0; 18 | const args = process.argv.slice(2); 19 | args.forEach(function (val, index, array) { 20 | const portMatch = /^--server=(\d{4,5})$/.exec(val); 21 | if (portMatch) { 22 | port = parseInt(portMatch[1], 10); 23 | } 24 | }); 25 | if (port > 0) { 26 | Net.createServer((socket) => { 27 | const session = new ovmDebug_1.OVMDebugSession(); 28 | session.setRunAsServer(true); 29 | session.start(socket, socket); 30 | }).listen(port); 31 | } 32 | else { 33 | // start a single session that communicates via stdin/stdout 34 | const session = new ovmDebug_1.OVMDebugSession(); 35 | process.on('SIGTERM', () => { 36 | session.shutdown(); 37 | }); 38 | session.start(process.stdin, process.stdout); 39 | } 40 | -------------------------------------------------------------------------------- /misc/vscode/textmate-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": { 3 | "id": "onyx", 4 | "aliases": [ "Onyx" ], 5 | "extensions": [ ".onyx" ] 6 | }, 7 | "grammar": { 8 | "language": "onyx", 9 | "scopeName": "source.onyx", 10 | "path": "./syntaxes/onyx.tmLanguage" 11 | }, 12 | "assignment": { 13 | "single": "none", 14 | "multiple": "none", 15 | "separator": "none" 16 | }, 17 | "exclude": "", 18 | "comments": { 19 | "lineComment": "comment.line.double-slash.onyx", 20 | "blockComment": [ "comment.block.onyx" ] 21 | }, 22 | "declarations": [ 23 | "entity.name.function.onyx", 24 | "entity.name.type.onyx", 25 | "entity.name.type.class.onyx", 26 | "entity.name.type.interface.onyx", 27 | "entity.name.type.enum.onyx", 28 | "entity.name.type.namespace.onyx", 29 | "entity.name.block.onyx", 30 | "entity.name.tag.onyx" 31 | ], 32 | "indentation": { 33 | "punctuation.block.begin.onyx": 1, 34 | "punctuation.block.end.onyx": -1 35 | }, 36 | "dedentation": [], 37 | "punctuation": { 38 | "continuation": "" 39 | }, 40 | "markers": { 41 | "start": "", 42 | "end": "" 43 | }, 44 | "symbols": { 45 | "entity.name.function.onyx": 11, 46 | "entity.name.type.namespace.onyx": 2, 47 | "entity.name.type.class.onyx": 4, 48 | "entity.name.type.interface.onyx": 10, 49 | "entity.name.type.enum.onyx": 9, 50 | "entity.name.type.onyx": 22 51 | } 52 | } -------------------------------------------------------------------------------- /misc/vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "moduleResolution": "node", 7 | "lib": ["es6", "es2016"], 8 | "sourceMap": false, 9 | "rootDir": ".", 10 | "typeRoots": [ 11 | "node_modules/@types" 12 | ] 13 | }, 14 | "exclude": ["node_modules", ".vscode-test"] 15 | } -------------------------------------------------------------------------------- /runtime/README.md: -------------------------------------------------------------------------------- 1 | # Onyx Runtime 2 | 3 | This part of the repo is for the runtime library that Onyx uses for: 4 | - Interacting with the file system 5 | - Querying system statistics 6 | - Much more 7 | 8 | 9 | -------------------------------------------------------------------------------- /runtime/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$(uname)" in 4 | Linux) suffix='so' ;; 5 | *BSD) suffix='so' ;; 6 | Darwin) suffix='dylib' ;; 7 | *) suffix='dll' ;; 8 | esac 9 | 10 | FLAGS="" 11 | if [ "$(uname)" = "Darwin" ]; then 12 | FLAGS="$FLAGS -framework Security" 13 | fi 14 | if [ ! -z ${ONYX_TARGET+x} ]; then 15 | FLAGS="$FLAGS --target=$ONYX_TARGET" 16 | fi 17 | 18 | 19 | echo "Compiling onyx_runtime.$suffix" 20 | $ONYX_CC -shared -fpic -w -O2 \ 21 | -o onyx_runtime.$suffix \ 22 | $FLAGS \ 23 | -I ../shared/include -I ../compiler/include \ 24 | ./onyx_runtime.c \ 25 | -lpthread 26 | -------------------------------------------------------------------------------- /runtime/src/ort_cptr.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // C-Pointers 4 | // 5 | // These are wildly unsafe and break the core principles of the security 6 | // of WebAssembly, so there should be a way to turn them off! 7 | // 8 | ONYX_DEF(__cptr_make, (WASM_I32), (WASM_I64)) { 9 | wasm_val_init_ptr(&results->data[0], ONYX_PTR(params->data[0].of.i32)); 10 | return NULL; 11 | } 12 | 13 | ONYX_DEF(__cptr_read, (WASM_I64, WASM_I32, WASM_I32), ()) { 14 | memcpy(ONYX_PTR(params->data[1].of.i32), (void *) params->data[0].of.i64, params->data[2].of.i32); 15 | return NULL; 16 | } 17 | 18 | ONYX_DEF(__cptr_read_u8, (WASM_I64), (WASM_I32)) { 19 | results->data[0] = WASM_I32_VAL(*(u8 *) params->data[0].of.i64); 20 | return NULL; 21 | } 22 | 23 | ONYX_DEF(__cptr_read_u16, (WASM_I64), (WASM_I32)) { 24 | results->data[0] = WASM_I32_VAL(*(u16 *) params->data[0].of.i64); 25 | return NULL; 26 | } 27 | 28 | ONYX_DEF(__cptr_read_u32, (WASM_I64), (WASM_I32)) { 29 | results->data[0] = WASM_I32_VAL(*(u32 *) params->data[0].of.i64); 30 | return NULL; 31 | } 32 | 33 | ONYX_DEF(__cptr_read_u64, (WASM_I64), (WASM_I64)) { 34 | results->data[0] = WASM_I64_VAL(*(u64 *) params->data[0].of.i64); 35 | return NULL; 36 | } 37 | 38 | ONYX_DEF(__cptr_extract_str, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { 39 | unsigned int len = strlen((char *) params->data[0].of.i64); 40 | 41 | if (params->data[2].of.i32 != 0) { 42 | strncpy(ONYX_PTR(params->data[1].of.i32), (char *) params->data[0].of.i64, params->data[2].of.i32); 43 | } 44 | 45 | results->data[0] = WASM_I32_VAL(len); 46 | return NULL; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /scripts/core_tests.onyx: -------------------------------------------------------------------------------- 1 | 2 | 3 | #load "core/module" 4 | 5 | use core {package, test} 6 | 7 | #inject core { 8 | Running_Tests :: true 9 | } 10 | 11 | main :: () { 12 | test.run_tests(); 13 | } 14 | -------------------------------------------------------------------------------- /scripts/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": { 3 | "name": { 4 | "type": "string", 5 | "description": "Name of the project" 6 | }, 7 | "description": { 8 | "type": "string", 9 | "description": "Description of the project" 10 | }, 11 | "url": { 12 | "type": "string", 13 | "description": "Git repository for project" 14 | }, 15 | "author": { 16 | "type": "string", 17 | "description": "Author name" 18 | } 19 | }, 20 | "files": { 21 | ".gitignore": "*.wasm\nlib\nbin", 22 | "onyx-lsp.ini": "[lsp]\nmode=project\nonyxFiles=src/main.onyx\nworkingDir=.", 23 | "onyx-pkg.ini": "[metadata]\nname={{name}}\ndescription={{description}}\nurl={{url}}\nauthor={{author}}\nversion=0.0.1\n", 24 | "src": { 25 | "main.onyx": "#load \"lib/packages\"\n\nuse core {*}\n\nmain :: () {\n println(\"Hello Onyx!\");\n}\n" 26 | } 27 | }, 28 | "commands": [ 29 | "git init" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /scripts/dist.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | FOLDERS := str.[ 4 | "compiler", 5 | "core", 6 | "interpreter", 7 | "runtime", 8 | "tests", 9 | "misc", 10 | "shared/lib/linux_x86_64", 11 | "shared/include", 12 | "examples/" 13 | ]; 14 | 15 | FILES := str.[ 16 | "README.md", 17 | "LICENSE", 18 | "CHANGELOG", 19 | "build.sh", 20 | "settings.sh", 21 | "scripts/onyx-pkg.onyx", 22 | "scripts/default.json", 23 | "scripts/run_tests.onyx", 24 | "bin/onyx-loader.js", 25 | "bin/onyx-thread.js" 26 | ] 27 | 28 | run :: (command: [] str) -> bool { 29 | cmd := command[0]; 30 | parts := command[1 .. command.length]; 31 | proc := os.process_spawn(cmd, parts); 32 | return os.process_wait(&proc) == .Success; 33 | } 34 | 35 | main :: () { 36 | args := array.make(.["tar", "cvzf", "onyx-latest-linux-source.tar.gz"]); 37 | 38 | for FOLDERS do args << it; 39 | for FILES do args << it; 40 | 41 | run(args); 42 | } 43 | -------------------------------------------------------------------------------- /settings.sh: -------------------------------------------------------------------------------- 1 | 2 | # Where Onyx will be installed from the "./build.sh install" command. 3 | export ONYX_INSTALL_DIR="$HOME/.onyx" 4 | 5 | # The compiler to use. Only GCC and TCC have been tested. 6 | export ONYX_CC='gcc' 7 | 8 | # The architecture of your system. If your not sure, leave this alone. 9 | export ONYX_ARCH="$(uname | tr '[:upper:]' '[:lower:]')_$(uname -m)" 10 | 11 | # export ONYX_RUNTIME_LIBRARY="ovmwasm" 12 | export ONYX_RUNTIME_LIBRARY="wasmer" 13 | 14 | # Enable Dynamic call 15 | export ONYX_USE_DYNCALL=1 16 | -------------------------------------------------------------------------------- /shared/LICENSE: -------------------------------------------------------------------------------- 1 | License for libdyncall. Contents below has been unmodified. 2 | 3 | If not stated otherwise inside a file, all files here are distributed in 4 | terms of: 5 | 6 | Copyright (c) 2007-2022 Daniel Adler , 7 | Tassilo Philipp 8 | 9 | Permission to use, copy, modify, and distribute this software for any 10 | purpose with or without fee is hereby granted, provided that the above 11 | copyright notice and this permission notice appear in all copies. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /shared/include/dyncall/dyncall_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Package: dyncall 4 | Library: dyncall 5 | File: dyncall/dyncall_config.h 6 | Description: Macro configuration file for non-standard C types 7 | License: 8 | 9 | Copyright (c) 2007-2018 Daniel Adler , 10 | Tassilo Philipp 11 | 12 | Permission to use, copy, modify, and distribute this software for any 13 | purpose with or without fee is hereby granted, provided that the above 14 | copyright notice and this permission notice appear in all copies. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 | 24 | */ 25 | 26 | 27 | 28 | /* 29 | 30 | dyncall type configuration 31 | 32 | REVISION 33 | 2007/12/11 initial 34 | 35 | */ 36 | 37 | #ifndef DYNCALL_CONFIG_H 38 | #define DYNCALL_CONFIG_H 39 | 40 | #include "dyncall_macros.h" 41 | 42 | #define DC_BOOL int 43 | #define DC_LONG_LONG long long 44 | #define DC_POINTER void* 45 | 46 | #endif /* DYNCALL_CONFIG_H */ 47 | 48 | -------------------------------------------------------------------------------- /shared/lib/README.md: -------------------------------------------------------------------------------- 1 | Onyx includes these external libraries: 2 | - wasmer: This is used to run WebAssembly directly from Onyx using 'onyx run'. Instead of relying on the host system to have Wasmer installed, it is included in the project. This will need to be updated as Wasmer is updated. 3 | - dyncall: Allows for dynamically calling arbitrary C function at runtime. 4 | -------------------------------------------------------------------------------- /shared/lib/darwin_amd64/lib/libdyncall_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_amd64/lib/libdyncall_s.a -------------------------------------------------------------------------------- /shared/lib/darwin_amd64/lib/libdyncallback_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_amd64/lib/libdyncallback_s.a -------------------------------------------------------------------------------- /shared/lib/darwin_arm64/lib/libdyncall_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_arm64/lib/libdyncall_s.a -------------------------------------------------------------------------------- /shared/lib/darwin_arm64/lib/libdyncallback_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_arm64/lib/libdyncallback_s.a -------------------------------------------------------------------------------- /shared/lib/darwin_arm64/lib/libovmwasm.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_arm64/lib/libovmwasm.a -------------------------------------------------------------------------------- /shared/lib/darwin_x86_64/lib/libdyncall_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_x86_64/lib/libdyncall_s.a -------------------------------------------------------------------------------- /shared/lib/darwin_x86_64/lib/libdyncallback_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/darwin_x86_64/lib/libdyncallback_s.a -------------------------------------------------------------------------------- /shared/lib/linux_aarch64/lib/libwasmer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/linux_aarch64/lib/libwasmer.so -------------------------------------------------------------------------------- /shared/lib/linux_x86_64/lib/libdyncall_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/linux_x86_64/lib/libdyncall_s.a -------------------------------------------------------------------------------- /shared/lib/linux_x86_64/lib/libdyncallback_s.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/linux_x86_64/lib/libdyncallback_s.a -------------------------------------------------------------------------------- /shared/lib/windows_x86_64/lib/wasmer.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanfh/onyx/3276f4f6cde5bdc6d118f15c93d4be35005e2974/shared/lib/windows_x86_64/lib/wasmer.lib -------------------------------------------------------------------------------- /tests/aoc-2020/day1: -------------------------------------------------------------------------------- 1 | Answer: 200637446 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day1.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core 4 | use core.io 5 | use core.array 6 | use core {printf} 7 | 8 | main :: (args: [] cstr) { 9 | contents := #file_contents "./input/day1.txt"; 10 | reader, stream := io.reader_from_string(contents); 11 | defer cfree(stream); 12 | 13 | nums := array.make(u32, 128); 14 | defer array.free(&nums); 15 | 16 | while num := 1; num > 0 { 17 | // This sets num to be 0 if there is no number 18 | num = io.read_u32(&reader); 19 | if num != 0 do array.push(&nums, num); 20 | } 21 | 22 | for i in nums do for j in nums do for k in nums { 23 | if j + i + k == 2020 { 24 | printf("Answer: {}\n", i * j * k); 25 | 26 | // Break out of all of the loops 27 | break break break; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/aoc-2020/day10: -------------------------------------------------------------------------------- 1 | Diff prod: 1820 2 | Arrangements: 3454189699072 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/day10.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | count_ending_paths :: (nums: [..] u32) -> u64 { 6 | tally := array.make(u64, nums.count); 7 | defer array.free(&tally); 8 | 9 | for &t in tally do *t = 0; 10 | tally[nums.count - 1] = 1; 11 | 12 | while i := cast(i32) (nums.count - 2); i >= 0 { 13 | for diff in 1 .. 4 { 14 | if i + diff >= nums.count do continue; 15 | 16 | if nums[i + diff] - nums[i] <= 3 do tally[i] += tally[i + diff]; 17 | } 18 | 19 | i -= 1; 20 | } 21 | 22 | return tally[0]; 23 | } 24 | 25 | main :: (args: [] cstr) { 26 | contents := #file_contents "./input/day10.txt"; 27 | 28 | file := contents; 29 | 30 | nums := array.make(u32); 31 | defer array.free(&nums); 32 | 33 | while !string.empty(file) { 34 | array.push(&nums, ~~ conv.parse_int(&file)); 35 | string.advance_line(&file); 36 | } 37 | 38 | // Slight hack, but having 0 in the array makes both parts easier 39 | array.push(&nums, 0); 40 | 41 | array.sort(nums, (a, b) => a - b); 42 | 43 | diffs: [3] u32; 44 | for &d in diffs do *d = 0; 45 | for i in 1 .. nums.count do diffs[nums[i] - nums[i - 1] - 1] += 1; 46 | diffs[2] += 1; 47 | 48 | printf("Diff prod: {}\n", diffs[0] * diffs[2]); 49 | printf("Arrangements: {}\n", count_ending_paths(nums)); 50 | } 51 | -------------------------------------------------------------------------------- /tests/aoc-2020/day11: -------------------------------------------------------------------------------- 1 | Occupied: 2027 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day12: -------------------------------------------------------------------------------- 1 | Ship distance: 20592 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day13: -------------------------------------------------------------------------------- 1 | Result: 800177252346225 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day14: -------------------------------------------------------------------------------- 1 | Sum: 4254673508445 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day15: -------------------------------------------------------------------------------- 1 | 2020th: 492 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day15.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | initial_numbers := u32.[ 1, 20, 8, 12, 0, 14 ]; 6 | 7 | spoken_times :: struct { 8 | recent : u32 = 0; 9 | previous : u32 = 0; 10 | } 11 | 12 | main :: (args: [] cstr) { 13 | // The current implementation of Map is rather slow at a large scale. 14 | // Any changes to the implementation of Map should be tested on this 15 | // file to validate if they 1) work and 2) are faster. 16 | nums := map.make(u32, spoken_times); 17 | defer map.free(&nums); 18 | 19 | turn := 1; 20 | last_num := 0; 21 | 22 | for n in initial_numbers { 23 | map.put(&nums, n, .{ recent = turn }); 24 | turn += 1; 25 | last_num = n; 26 | } 27 | 28 | while turn != 2021 { 29 | st := map.get(&nums, last_num) ?? .{}; 30 | 31 | if st.previous == 0 do last_num = 0; 32 | else do last_num = st.recent - st.previous; 33 | 34 | st = map.get(&nums, last_num) ?? .{}; 35 | st.previous = st.recent; 36 | st.recent = turn; 37 | map.put(&nums, last_num, st); 38 | 39 | turn += 1; 40 | } 41 | 42 | printf("2020th: {}\n", last_num); 43 | } 44 | -------------------------------------------------------------------------------- /tests/aoc-2020/day16: -------------------------------------------------------------------------------- 1 | Scanning error: 27898 2 | Departure multiply: 2766491048287 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/day17: -------------------------------------------------------------------------------- 1 | Active count: 2192 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day18: -------------------------------------------------------------------------------- 1 | Total: 283729053022731 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day18.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | parse_factor :: (file: &str) -> u64 { 6 | string.strip_leading_whitespace(file); 7 | 8 | switch file.data[0] { 9 | case #char "0" .. #char "9" { 10 | return conv.parse_int(file); 11 | } 12 | 13 | case #char "(" { 14 | string.advance(file, 1); 15 | 16 | value := parse_expression_mul(file); 17 | 18 | string.strip_leading_whitespace(file); 19 | string.advance(file, 1); 20 | 21 | return value; 22 | } 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | parse_expression_add :: (file: &str) -> u64 { 29 | string.strip_leading_whitespace(file); 30 | 31 | left := parse_factor(file); 32 | 33 | string.strip_leading_whitespace(file); 34 | while file.data[0] == #char "+" { 35 | op := file.data[0]; 36 | string.advance(file, 1); 37 | 38 | right := parse_factor(file); 39 | 40 | left += right; 41 | 42 | string.strip_leading_whitespace(file); 43 | } 44 | 45 | return left; 46 | } 47 | 48 | parse_expression_mul :: (file: &str) -> u64 { 49 | string.strip_leading_whitespace(file); 50 | 51 | left := parse_expression_add(file); 52 | 53 | string.strip_leading_whitespace(file); 54 | while file.data[0] == #char "*" { 55 | op := file.data[0]; 56 | string.advance(file, 1); 57 | 58 | right := parse_expression_add(file); 59 | 60 | left *= right; 61 | 62 | string.strip_leading_whitespace(file); 63 | } 64 | 65 | return left; 66 | } 67 | 68 | main :: (args: [] cstr) { 69 | contents := #file_contents "./input/day18.txt"; 70 | file := contents; 71 | 72 | total: u64 = 0; 73 | while !string.empty(file) { 74 | total += parse_expression_mul(&file); 75 | } 76 | 77 | printf("Total: {}\n", total); 78 | } 79 | -------------------------------------------------------------------------------- /tests/aoc-2020/day19: -------------------------------------------------------------------------------- 1 | Valid count: 369 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day2: -------------------------------------------------------------------------------- 1 | Number valid: 482 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day2.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | #load "core/module" 4 | 5 | use core {*} 6 | 7 | main :: (args: [] cstr) { 8 | contents := #file_contents "./input/day2.txt"; 9 | reader, stream := io.reader_from_string(contents); 10 | defer cfree(stream); 11 | 12 | valid := 0; 13 | 14 | while !io.reader_empty(&reader) { 15 | lo := io.read_u32(&reader); 16 | 17 | io.read_byte(&reader); 18 | hi := io.read_u32(&reader); 19 | 20 | io.read_byte(&reader); 21 | ch := io.read_byte(&reader); 22 | 23 | io.skip_bytes(&reader, 2); 24 | pw := io.read_line(&reader); 25 | 26 | // Part 1 27 | // count := 0; 28 | // for c in pw do if c == ch do count += 1; 29 | // if count >= lo && count <= hi do valid += 1; 30 | 31 | // Part 2 32 | count := 0; 33 | if pw[lo - 1] == ch do count += 1; 34 | if pw[hi - 1] == ch do count += 1; 35 | if count == 1 do valid += 1; 36 | } 37 | 38 | printf("Number valid: {}\n", valid); 39 | } 40 | -------------------------------------------------------------------------------- /tests/aoc-2020/day20: -------------------------------------------------------------------------------- 1 | Corner product: 104831106565027 2 | Safe count: 2093 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/day21: -------------------------------------------------------------------------------- 1 | Total safe: 2779 2 | lkv -> dairy 3 | lfcppl -> eggs 4 | jhsrjlj -> nuts 5 | jrhvk -> peanuts 6 | zkls -> sesame 7 | qjltjd -> shellfish 8 | xslr -> soy 9 | rfpbpn -> wheat 10 | lkv,lfcppl,jhsrjlj,jrhvk,zkls,qjltjd,xslr,rfpbpn, 11 | (Don't copy the last ','!) 12 | -------------------------------------------------------------------------------- /tests/aoc-2020/day22: -------------------------------------------------------------------------------- 1 | Answer: 32598 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day23: -------------------------------------------------------------------------------- 1 | Cup product: 287230227046 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day24: -------------------------------------------------------------------------------- 1 | Black count: 473 2 | GOL black count: 4070 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/day25: -------------------------------------------------------------------------------- 1 | 18329280 == 18329280 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day3: -------------------------------------------------------------------------------- 1 | Tree product: 7812180000 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day3.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | Point :: struct { 6 | x, y : i32; 7 | } 8 | 9 | LineInterp :: struct { 10 | ox, oy : i32; 11 | dx, dy : i32; 12 | } 13 | 14 | line_interp_at :: (use li: LineInterp, t: i32) -> Point { 15 | return .{ ox + dx * t, oy + dy * t }; 16 | } 17 | 18 | main :: (args: [] cstr) { 19 | contents := #file_contents "./input/day3.txt"; 20 | 21 | forest := array.make(u8, 1024); 22 | defer array.free(&forest); 23 | 24 | width := 0; 25 | height := 0; 26 | while true { 27 | line := string.read_until(&contents, #char "\n"); 28 | string.advance(&contents, 1); 29 | if line.count == 0 do break; 30 | 31 | width = line.count; 32 | height = height + 1; 33 | 34 | for ch in line do array.push(&forest, ch); 35 | } 36 | 37 | lis := LineInterp.[ 38 | .{ 0, 0, 1, 1 }, 39 | .{ 0, 0, 3, 1 }, 40 | .{ 0, 0, 5, 1 }, 41 | .{ 0, 0, 7, 1 }, 42 | .{ 0, 0, 1, 2 }, 43 | ]; 44 | 45 | tree_prod: u64 = 1; 46 | 47 | for li in lis { 48 | tree_count: u64 = 0; 49 | while i := 0; true { 50 | p := line_interp_at(li, i); 51 | if p.y >= height || p.y < 0 do break; 52 | i += 1; 53 | 54 | p.x %= width; 55 | 56 | if forest[p.x + p.y * width] == #char "#" do tree_count += 1; 57 | } 58 | 59 | tree_prod *= tree_count; 60 | } 61 | 62 | printf("Tree product: {}\n", tree_prod); 63 | } 64 | -------------------------------------------------------------------------------- /tests/aoc-2020/day4: -------------------------------------------------------------------------------- 1 | Valid passports: 206 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day4.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | // Returns the number of fields 6 | process_passport :: (contents: &str) -> u32 { 7 | field_count := 0; 8 | 9 | while true { 10 | line := string.read_until(contents, #char "\n"); 11 | string.advance(contents, 1); 12 | if line.count == 0 do break; 13 | 14 | fields := string.split(line, #char " "); 15 | defer cfree(fields.data); 16 | 17 | for field in fields { 18 | data := string.split(field, #char ":"); 19 | defer cfree(data.data); 20 | 21 | if !string.equal(data[0], "cid") { 22 | field_count += 1; 23 | } 24 | } 25 | } 26 | 27 | return field_count; 28 | } 29 | 30 | // This does not include part 2 because it is gross and 31 | // not worth the effort to implement it. 32 | main :: (args: [] cstr) { 33 | contents := #file_contents "./input/day4.txt"; 34 | 35 | valid_passports := 0; 36 | while true { 37 | if contents.count == 0 do break; 38 | 39 | field_count := process_passport(&contents); 40 | if field_count == 7 do valid_passports += 1; 41 | } 42 | 43 | printf("Valid passports: {}\n", valid_passports); 44 | } 45 | -------------------------------------------------------------------------------- /tests/aoc-2020/day5: -------------------------------------------------------------------------------- 1 | Max val: 926 2 | Your seat: 657 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/day5.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | contents := #file_contents "./input/day5.txt"; 7 | 8 | vals := array.make(u32); 9 | defer array.free(&vals); 10 | 11 | max_val := 0; 12 | 13 | while true { 14 | line := string.read_until(&contents, #char "\n"); 15 | string.advance(&contents); 16 | if line.count == 0 do break; 17 | 18 | val := 0; 19 | for ch in line { 20 | val *= 2; 21 | if ch == #char "B" || ch == #char "R" do val += 1; 22 | } 23 | 24 | max_val = math.max(max_val, val); 25 | array.push(&vals, val); 26 | } 27 | 28 | missing := 0; 29 | array.sort(vals, cmp_asc); 30 | for i in 0 .. vals.count - 1 { 31 | if vals[i + 1] - vals[i] != 1 do missing = vals[i] + 1; 32 | } 33 | 34 | printf("Max val: {}\n", max_val); 35 | printf("Your seat: {}\n", missing); 36 | } 37 | 38 | cmp_asc :: (a: $T, b: T) -> i32 do return ~~(a - b); 39 | -------------------------------------------------------------------------------- /tests/aoc-2020/day6: -------------------------------------------------------------------------------- 1 | Unique sum: 6585 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day6.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | part_1 :: (contents: &str) -> u32 { 6 | chars : [26] bool; 7 | for &ch in chars do *ch = false; 8 | 9 | while true { 10 | line := string.read_until(contents, #char "\n"); 11 | string.advance(contents, 1); 12 | if line.count == 0 do break; 13 | 14 | for ch in line do chars[~~ch - cast(u32) #char "a"] = true; 15 | } 16 | 17 | sum := 0; 18 | for ch in chars do if ch do sum += 1; 19 | 20 | return sum; 21 | } 22 | 23 | part_2 :: (contents: &str) -> u32 { 24 | chars : [26] u32; 25 | for &ch in chars do *ch = 0; 26 | 27 | person_count := 0; 28 | while true { 29 | line := string.read_until(contents, #char "\n"); 30 | string.advance(contents, 1); 31 | if line.count == 0 do break; 32 | 33 | person_count += 1; 34 | 35 | for ch in line do chars[~~ch - cast(u32) #char "a"] += 1; 36 | } 37 | 38 | sum := 0; 39 | for ch in chars do if ch == person_count do sum += 1; 40 | 41 | return sum; 42 | } 43 | 44 | main :: (args: [] cstr) { 45 | contents := #file_contents "./input/day6.txt"; 46 | 47 | unique_sum := 0; 48 | while true { 49 | if contents.count == 0 do break; 50 | 51 | unique := part_1(&contents); 52 | unique_sum += unique; 53 | } 54 | 55 | printf("Unique sum: {}\n", unique_sum); 56 | } 57 | -------------------------------------------------------------------------------- /tests/aoc-2020/day7: -------------------------------------------------------------------------------- 1 | Count: 30899 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day8: -------------------------------------------------------------------------------- 1 | Accumulator value: 1033 2 | -------------------------------------------------------------------------------- /tests/aoc-2020/day9: -------------------------------------------------------------------------------- 1 | Invalid number: 248131121 2 | Extrema sum: 31580383 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/input/day10.txt: -------------------------------------------------------------------------------- 1 | 17 2 | 110 3 | 146 4 | 144 5 | 70 6 | 57 7 | 124 8 | 121 9 | 134 10 | 12 11 | 135 12 | 120 13 | 19 14 | 92 15 | 6 16 | 103 17 | 46 18 | 56 19 | 93 20 | 65 21 | 14 22 | 31 23 | 63 24 | 41 25 | 131 26 | 60 27 | 73 28 | 83 29 | 71 30 | 37 31 | 85 32 | 79 33 | 13 34 | 7 35 | 109 36 | 24 37 | 94 38 | 2 39 | 30 40 | 3 41 | 27 42 | 77 43 | 91 44 | 106 45 | 123 46 | 128 47 | 35 48 | 26 49 | 112 50 | 55 51 | 97 52 | 21 53 | 100 54 | 88 55 | 113 56 | 117 57 | 25 58 | 82 59 | 129 60 | 66 61 | 11 62 | 116 63 | 64 64 | 78 65 | 38 66 | 99 67 | 130 68 | 84 69 | 98 70 | 72 71 | 50 72 | 36 73 | 54 74 | 8 75 | 34 76 | 20 77 | 127 78 | 1 79 | 137 80 | 143 81 | 76 82 | 69 83 | 111 84 | 136 85 | 53 86 | 43 87 | 140 88 | 145 89 | 49 90 | 122 91 | 18 92 | 42 93 | -------------------------------------------------------------------------------- /tests/aoc-2020/input/day13.txt: -------------------------------------------------------------------------------- 1 | 1006697 2 | 13,x,x,41,x,x,x,x,x,x,x,x,x,641,x,x,x,x,x,x,x,x,x,x,x,19,x,x,x,x,17,x,x,x,x,x,x,x,x,x,x,x,29,x,661,x,x,x,x,x,37,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,23 3 | -------------------------------------------------------------------------------- /tests/aoc-2020/input/day15.txt: -------------------------------------------------------------------------------- 1 | 1,20,8,12,0,14 -------------------------------------------------------------------------------- /tests/aoc-2020/input/day17.txt: -------------------------------------------------------------------------------- 1 | .#.#.#.. 2 | ..#....# 3 | #####..# 4 | #####..# 5 | #####..# 6 | ###..#.# 7 | #..##.## 8 | #.#.#### -------------------------------------------------------------------------------- /tests/aoc-2020/input/day22.txt: -------------------------------------------------------------------------------- 1 | Player 1: 2 | 44 3 | 24 4 | 36 5 | 6 6 | 27 7 | 46 8 | 33 9 | 45 10 | 47 11 | 41 12 | 15 13 | 23 14 | 40 15 | 38 16 | 43 17 | 42 18 | 25 19 | 5 20 | 30 21 | 35 22 | 34 23 | 13 24 | 29 25 | 1 26 | 50 27 | 28 | Player 2: 29 | 32 30 | 28 31 | 4 32 | 12 33 | 9 34 | 21 35 | 48 36 | 18 37 | 31 38 | 39 39 | 20 40 | 16 41 | 3 42 | 37 43 | 49 44 | 7 45 | 17 46 | 22 47 | 8 48 | 26 49 | 2 50 | 14 51 | 11 52 | 19 53 | 10 54 | -------------------------------------------------------------------------------- /tests/aoc-2020/input/day25.txt: -------------------------------------------------------------------------------- 1 | 12092626 2 | 4707356 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day01: -------------------------------------------------------------------------------- 1 | Part 1: 1564 2 | Part 2: 1611 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day01.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core.io 4 | use core.os 5 | use core {printf} 6 | 7 | count_increasing :: (arr: [] $T) -> u32 { 8 | increased_count := 0; 9 | for 1 .. arr.count { 10 | if arr[it - 1] < arr[it] { 11 | increased_count += 1; 12 | } 13 | } 14 | 15 | return increased_count; 16 | } 17 | 18 | main :: (args) => { 19 | file := os.open("./tests/aoc-2021/input/day01.txt")->expect("Error opening file"); 20 | reader := io.reader_make(&file); 21 | defer os.close(&file); 22 | 23 | nums: [..] i32; 24 | while !io.reader_empty(&reader) { 25 | nums << io.read_u32(&reader); 26 | io.skip_whitespace(&reader); 27 | } 28 | 29 | { // Part 1 30 | increased_count := count_increasing(nums); 31 | printf("Part 1: {}\n", increased_count); 32 | } 33 | 34 | { // Part 2 35 | windows: [..] i32; 36 | for i in range.{ 0, nums.count - 2 } { 37 | sum := 0; 38 | for k in i .. i+3 do sum += nums[k]; 39 | windows << sum; 40 | } 41 | 42 | increased_count := count_increasing(windows); 43 | printf("Part 2: {}\n", increased_count); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/aoc-2021/day02: -------------------------------------------------------------------------------- 1 | Part 2: 1965970888 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day02.onyx: -------------------------------------------------------------------------------- 1 | PART :: 2 2 | 3 | use core {*} 4 | 5 | main :: (args) => { 6 | for file in os.with_file("tests/aoc-2021/input/day02.txt") { 7 | reader := io.reader_make(file); 8 | 9 | #if PART == 1 { 10 | horizontal, vertical := 0, 0; 11 | while !io.reader_empty(&reader) { 12 | parts := string.split(io.read_line(&reader, inplace=true), #char " "); 13 | defer memory.free_slice(&parts); 14 | 15 | value := cast(i32) conv.str_to_i64(parts[1]); 16 | switch parts[0] { 17 | case "forward" do horizontal += value; 18 | case "down" do vertical += value; 19 | case "up" do vertical -= value; 20 | } 21 | } 22 | 23 | printf("Part 1: {}\n", horizontal * vertical); 24 | } 25 | 26 | #if PART == 2 { 27 | horizontal, vertical, aim : i64; 28 | horizontal, vertical, aim = 0, 0, 0; 29 | while !io.reader_empty(&reader) { 30 | parts := string.split(io.read_line(&reader, inplace=true), #char " "); 31 | defer memory.free_slice(&parts); 32 | 33 | value := conv.str_to_i64(parts[1]); 34 | switch parts[0] { 35 | case "forward" { 36 | horizontal += value; 37 | vertical += aim * value; 38 | } 39 | case "down" do aim += value; 40 | case "up" do aim -= value; 41 | } 42 | } 43 | 44 | printf("Part 2: {}\n", horizontal * vertical); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /tests/aoc-2021/day03: -------------------------------------------------------------------------------- 1 | Part 1: 738234 2 | Part 2: 3969126 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day04: -------------------------------------------------------------------------------- 1 | Part 1: 67716 2 | Part 2: 1830 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day05: -------------------------------------------------------------------------------- 1 | Part 2: 19676 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day06: -------------------------------------------------------------------------------- 1 | Part 2: 1767323539209 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day06.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args) => { 6 | for file in os.with_file("./tests/aoc-2021/input/day06.txt") { 7 | reader := io.reader_make(file); 8 | start_str := io.read_all(&reader); 9 | 10 | start_list := string.split(start_str, #char ","); 11 | 12 | fish: [9] i64; 13 | for start_list { 14 | value := cast(i32) conv.str_to_i64(it); 15 | fish[value] += 1; 16 | } 17 | 18 | for day in 256 { 19 | new_fish := fish[0]; 20 | for 8 do fish[it] = fish[it + 1]; 21 | fish[6] += new_fish; 22 | fish[8] = new_fish; 23 | } 24 | 25 | total := array.sum(fish); 26 | printf("Part 2: {}\n", total); 27 | } 28 | } -------------------------------------------------------------------------------- /tests/aoc-2021/day07: -------------------------------------------------------------------------------- 1 | Part 2: 489 with fuel 104822130 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day07.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args) => { 6 | for file in os.with_file("./tests/aoc-2021/input/day07.txt") { 7 | reader := io.reader_make(file); 8 | nums := io.read_all(&reader) 9 | |> string.split(#char ",") 10 | |> iter.as_iter() 11 | |> iter.map((x) => cast(i32) conv.parse_int(x)) 12 | |> iter.to_array(); 13 | 14 | min := array.fold(nums, nums[0], math.min); 15 | max := array.fold(nums, nums[0], math.max); 16 | 17 | min_cost := 0x7fffffff; 18 | best_middle := 0; 19 | for middle in min .. max { 20 | total_cost := 0; 21 | for nums { 22 | dist := math.abs(it - middle); 23 | total_cost += dist * (dist + 1) / 2; // math.choose(dist + 1, 2); 24 | } 25 | 26 | if total_cost < min_cost { 27 | min_cost = total_cost; 28 | best_middle = middle; 29 | } 30 | } 31 | 32 | printf("Part 2: {} with fuel {}\n", best_middle, min_cost); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/aoc-2021/day08: -------------------------------------------------------------------------------- 1 | Part 2: 974512 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day09: -------------------------------------------------------------------------------- 1 | Part 1: 575 2 | Part 2: 1019700 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day10: -------------------------------------------------------------------------------- 1 | Part 1: 339477 2 | [ 39987, 40412, 211418, 2961184, 18263624, 32699791, 34608922, 77999081, 143979073, 192930339, 219835591, 229509097, 481071808, 610107088, 621817986, 715998574, 726037067, 867149788, 940233121, 944880336, 1151348456, 1952645587, 2342374308, 2368462459, 3049320156, 3159526836, 3338592468, 3529238356, 3981995374, 4048632297, 4472552966, 5195055344, 5223271481, 5263640441, 5358005998, 5543505166, 5837871587, 5932417192, 6072890531, 9641557042, 10084664733, 17746755972, 20591383546, 20698042322, 21616583974, 23920462366, 24143557159, 26737415431, 30269373313 ] 3 | Part 2: 3049320156 4 | -------------------------------------------------------------------------------- /tests/aoc-2021/day11: -------------------------------------------------------------------------------- 1 | Part 1: 1669 2 | Part 2: 351 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day12: -------------------------------------------------------------------------------- 1 | Part 2: 149385 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day13: -------------------------------------------------------------------------------- 1 | Part 1: 687 2 | Part 2: 3 | XXXX XX X X XX X X XXX XXXX XX 4 | X X X X X X X X X X X X X X 5 | XXX X XX X XX XXX X X 6 | X X XX X X X X X X X X X XX 7 | X X X X X X X X X X X X X X 8 | X XXX X X XX X X XXX XXXX XXX 9 | 10 | -------------------------------------------------------------------------------- /tests/aoc-2021/day14: -------------------------------------------------------------------------------- 1 | { 2 | H => 206420145579 3 | S => 252943215762 4 | C => 422415532942 5 | K => 193200271244 6 | P => 6287180922765 7 | F => 12464638059775 8 | B => 211999150163 9 | O => 198828019091 10 | V => 274816464465 11 | N => 378279145958 12 | } 13 | Part 2: 12271437788530 14 | -------------------------------------------------------------------------------- /tests/aoc-2021/day15: -------------------------------------------------------------------------------- 1 | Part 2: 2868 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/day16: -------------------------------------------------------------------------------- 1 | Part 1: 940 2 | Part 2: 13476220616073 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day17: -------------------------------------------------------------------------------- 1 | Part 1: 15400 2 | Part 2: 5844 3 | -------------------------------------------------------------------------------- /tests/aoc-2021/day17.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | tx0: i32 6 | ty0: i32 7 | tx1: i32 8 | ty1: i32 9 | 10 | simulate :: (dx, dy: i32) -> (i32, bool) { 11 | x, y := 0, 0; 12 | maxy := 0; 13 | did_enter := false; 14 | while y >= math.min(ty1, ty0) && x <= math.max(tx1, tx0) { 15 | x += dx; 16 | y += dy; 17 | if dx > 0 do dx -= 1; 18 | if dx < 0 do dx += 1; 19 | dy -= 1; 20 | 21 | maxy = math.max(y, maxy); 22 | if tx0 <= x && x <= tx1 && ty0 <= y && y <= ty1 { 23 | did_enter = true; 24 | } 25 | } 26 | 27 | return maxy, did_enter; 28 | } 29 | 30 | 31 | main :: (args) => { 32 | 33 | for file in os.with_file("./tests/aoc-2021/input/day17.txt") { 34 | reader := io.reader_make(file); 35 | 36 | io.skip_bytes(&reader, 15); 37 | tx0 = io.read_i32(&reader); 38 | io.skip_bytes(&reader, 2); 39 | tx1 = io.read_i32(&reader); 40 | io.skip_bytes(&reader, 4); 41 | ty0 = io.read_i32(&reader); 42 | io.skip_bytes(&reader, 2); 43 | ty1 = io.read_i32(&reader); 44 | } 45 | 46 | max := 0; 47 | count := 0; 48 | 49 | for dx in 1 .. 1000 { 50 | for dy in -1000 .. 1000 { 51 | my, s := simulate(dx, dy); 52 | if s { 53 | max = math.max(my, max); 54 | count += 1; 55 | } 56 | } 57 | } 58 | 59 | printf("Part 1: {}\n", max); 60 | printf("Part 2: {}\n", count); 61 | } 62 | -------------------------------------------------------------------------------- /tests/aoc-2021/day18: -------------------------------------------------------------------------------- 1 | 4864 2 | i: [[[[2,9],6],[[2,8],9]],[[[0,5],6],[[6,1],7]]] 3 | j: [[[[9,6],[5,8]],[6,2]],[[[8,0],[7,0]],[[5,6],4]]] 4 | -------------------------------------------------------------------------------- /tests/aoc-2021/day21: -------------------------------------------------------------------------------- 1 | 995904 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/input/day06.txt: -------------------------------------------------------------------------------- 1 | 1,1,1,2,1,1,2,1,1,1,5,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,4,1,1,1,1,3,1,1,3,1,1,1,4,1,5,1,3,1,1,1,1,1,5,1,1,1,1,1,5,5,2,5,1,1,2,1,1,1,1,3,4,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,5,4,1,1,1,1,1,5,1,2,4,1,1,1,1,1,3,3,2,1,1,4,1,1,5,5,1,1,1,1,1,2,5,1,4,1,1,1,1,1,1,2,1,1,5,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,3,1,3,1,4,1,5,4,1,1,2,1,1,5,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,5,4,1,2,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,4,1,1,1,2,1,4,1,1,1,1,1,1,1,1,1,4,2,1,2,1,1,4,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,3,2,1,4,1,5,1,1,1,4,5,1,1,1,1,1,1,5,1,1,5,1,2,1,1,2,4,1,1,2,1,5,5,3 -------------------------------------------------------------------------------- /tests/aoc-2021/input/day11.txt: -------------------------------------------------------------------------------- 1 | 6788383436 2 | 5526827441 3 | 4582435866 4 | 5152547273 5 | 3746433621 6 | 2465145365 7 | 6324887128 8 | 8537558745 9 | 4718427562 10 | 2283324746 -------------------------------------------------------------------------------- /tests/aoc-2021/input/day12.txt: -------------------------------------------------------------------------------- 1 | VJ-nx 2 | start-sv 3 | nx-UL 4 | FN-nx 5 | FN-zl 6 | end-VJ 7 | sv-hi 8 | em-VJ 9 | start-hi 10 | sv-em 11 | end-zl 12 | zl-em 13 | hi-VJ 14 | FN-em 15 | start-VJ 16 | jx-FN 17 | zl-sv 18 | FN-sv 19 | FN-hi 20 | nx-end -------------------------------------------------------------------------------- /tests/aoc-2021/input/day14.txt: -------------------------------------------------------------------------------- 1 | KHSSCSKKCPFKPPBBOKVF 2 | 3 | BB -> C 4 | BC -> B 5 | BF -> N 6 | BH -> F 7 | BK -> V 8 | BN -> O 9 | BO -> F 10 | BP -> O 11 | BS -> K 12 | BV -> F 13 | CB -> V 14 | CC -> S 15 | CF -> H 16 | CH -> H 17 | CK -> C 18 | CN -> O 19 | CO -> B 20 | CP -> V 21 | CS -> P 22 | CV -> N 23 | FB -> V 24 | FC -> V 25 | FF -> P 26 | FH -> F 27 | FK -> K 28 | FN -> C 29 | FO -> F 30 | FP -> F 31 | FS -> C 32 | FV -> K 33 | HB -> N 34 | HC -> P 35 | HF -> K 36 | HH -> F 37 | HK -> H 38 | HN -> B 39 | HO -> S 40 | HP -> H 41 | HS -> K 42 | HV -> B 43 | KB -> C 44 | KC -> P 45 | KF -> H 46 | KH -> V 47 | KK -> N 48 | KN -> V 49 | KO -> O 50 | KP -> B 51 | KS -> C 52 | KV -> B 53 | NB -> N 54 | NC -> K 55 | NF -> F 56 | NH -> C 57 | NK -> S 58 | NN -> F 59 | NO -> H 60 | NP -> H 61 | NS -> C 62 | NV -> N 63 | OB -> V 64 | OC -> C 65 | OF -> V 66 | OH -> B 67 | OK -> F 68 | ON -> S 69 | OO -> K 70 | OP -> S 71 | OS -> N 72 | OV -> V 73 | PB -> F 74 | PC -> O 75 | PF -> F 76 | PH -> N 77 | PK -> H 78 | PN -> F 79 | PO -> H 80 | PP -> H 81 | PS -> C 82 | PV -> V 83 | SB -> K 84 | SC -> C 85 | SF -> H 86 | SH -> V 87 | SK -> B 88 | SN -> B 89 | SO -> C 90 | SP -> F 91 | SS -> P 92 | SV -> H 93 | VB -> V 94 | VC -> S 95 | VF -> F 96 | VH -> B 97 | VK -> O 98 | VN -> B 99 | VO -> B 100 | VP -> P 101 | VS -> K 102 | VV -> N -------------------------------------------------------------------------------- /tests/aoc-2021/input/day16.txt: -------------------------------------------------------------------------------- 1 | E0525D9802FA00B80021B13E2D4260004321DC648D729DD67B2412009966D76C0159ED274F6921402E9FD4AC1B0F652CD339D7B82240083C9A54E819802B369DC0082CF90CF9280081727DAF41E6A5C1B9B8E41A4F31A4EF67E2009834015986F9ABE41E7D6080213931CB004270DE5DD4C010E00D50401B8A708E3F80021F0BE0A43D9E460007E62ACEE7F9FB4491BC2260090A573A876B1BC4D679BA7A642401434937C911CD984910490CCFC27CC7EE686009CFC57EC0149CEFE4D135A0C200C0F401298BCF265377F79C279F540279ACCE5A820CB044B62299291C0198025401AA00021D1822BC5C100763A4698FB350E6184C00A9820200FAF00244998F67D59998F67D5A93ECB0D6E0164D709A47F5AEB6612D1B1AC788846008780252555097F51F263A1CA00C4D0946B92669EE47315060081206C96208B0B2610E7B389737F3E2006D66C1A1D4ABEC3E1003A3B0805D337C2F4FA5CD83CE7DA67A304E9BEEF32DCEF08A400020B1967FC2660084BC77BAC3F847B004E6CA26CA140095003900BAA3002140087003D40080022E8C00870039400E1002D400F10038C00D100218038F400B6100229500226699FEB9F9B098021A00800021507627C321006E24C5784B160C014A0054A64E64BB5459DE821803324093AEB3254600B4BF75C50D0046562F72B1793004667B6E78EFC0139FD534733409232D7742E402850803F1FA3143D00042226C4A8B800084C528FD1527E98D5EB45C6003FE7F7FCBA000A1E600FC5A8311F08010983F0BA0890021F1B61CC4620140EC010100762DC4C8720008641E89F0866259AF460C015D00564F71ED2935993A539C0F9AA6B0786008D80233514594F43CDD31F585005A25C3430047401194EA649E87E0CA801D320D2971C95CAA380393AF131F94F9E0499A775460 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/input/day17.txt: -------------------------------------------------------------------------------- 1 | target area: x=79..137, y=-176..-117 2 | -------------------------------------------------------------------------------- /tests/aoc-2021/input/day21.txt: -------------------------------------------------------------------------------- 1 | Player 1 starting position: 3 2 | Player 2 starting position: 4 -------------------------------------------------------------------------------- /tests/array_accessors: -------------------------------------------------------------------------------- 1 | true 2 | true 3 | true 4 | true 5 | true 6 | true 7 | true 8 | true 9 | true 10 | true 11 | true 12 | true 13 | true 14 | true 15 | true 16 | true 17 | true 18 | true 19 | true 20 | true 21 | true 22 | true 23 | -------------------------------------------------------------------------------- /tests/array_accessors.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: () { 6 | a: [2]f32; 7 | 8 | println(a.x == 0); 9 | println(a.y == 0); 10 | println(a.r == 0); 11 | println(a.g == 0); 12 | 13 | a.x = 10; 14 | a.y = 20; 15 | 16 | println(a.x == 10); 17 | println(a.y == 20); 18 | println(a.r == 10); 19 | println(a.g == 20); 20 | 21 | b := f32.[0, 0, 0]; 22 | b.r = 3; 23 | b.g = 2; 24 | b.b = 1; 25 | 26 | println(b.x == 3); 27 | println(b.y == 2); 28 | println(b.z == 1); 29 | println(b.r == 3); 30 | println(b.g == 2); 31 | println(b.b == 1); 32 | 33 | c := f32.[0, 0, 0, 0]; 34 | c.r, c.g, c.b, c.a = 1, 2, 3, 4; 35 | c.x, c.y, c.z, c.w = 1, 2, 3, 4; 36 | 37 | println(c.x == 1); 38 | println(c.y == 2); 39 | println(c.z == 3); 40 | println(c.w == 4); 41 | 42 | println(c.r == 1); 43 | println(c.g == 2); 44 | println(c.b == 3); 45 | println(c.a == 4); 46 | } 47 | -------------------------------------------------------------------------------- /tests/array_programming: -------------------------------------------------------------------------------- 1 | true 2 | true 3 | [ 2, 4, 5, 8 ] 4 | [ 2, 4, 6, 8 ] 5 | true 6 | true 7 | true 8 | -------------------------------------------------------------------------------- /tests/array_programming.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: () { 6 | a := i32.[ 1, 2, 3, 4 ]; 7 | b := i32.[ 1, 2, 3, 4 ]; 8 | 9 | println(a == b); 10 | b.z = 2; 11 | println(a != b); 12 | 13 | c := a + b; 14 | println(c); 15 | 16 | d := a * 2; 17 | println(d); 18 | 19 | e := d / 2; 20 | println(e == a); 21 | 22 | f := a - a; 23 | println(f.count == a.count); 24 | println(f == i32.[ 0, 0, 0, 0 ]); 25 | } 26 | -------------------------------------------------------------------------------- /tests/array_struct_robustness: -------------------------------------------------------------------------------- 1 | Array of structs on the stack. 2 | Vec2(4039, 7782) 3 | Array of structs from function call. 4 | Vec2(0, 0) 5 | Vec2(1, 1) 6 | Vec2(4, 8) 7 | Vec2(9, 27) 8 | Array of structs on a struct. 9 | Vec2(3, 9) 10 | Vec2(3, 27) 11 | Array of structs on a struct from function call. 12 | Vec2(25, 125) 13 | Vec2(100, 1000) 14 | Array of u32. 15 | 63001 16 | 2D-array from an allocation to a function. 17 | Vec2(1000, 2000) 18 | Vec2(1001, 2001) 19 | Vec2(1002, 2004) 20 | Vec2(1003, 2009) 21 | Vec2(1004, 2016) 22 | Vec2(1005, 2025) 23 | Vec2(1006, 2036) 24 | Vec2(1007, 2049) 25 | -------------------------------------------------------------------------------- /tests/arrow_notation: -------------------------------------------------------------------------------- 1 | (4, 6) 2 | (4, 6) 3 | (4, 6) 4 | -------------------------------------------------------------------------------- /tests/arrow_notation.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core 4 | use core.conv 5 | 6 | use core {println} 7 | 8 | #tag conv.Custom_Format.{format} 9 | V2 :: struct { 10 | x, y: i32; 11 | 12 | add :: (v1, v2: V2) => V2.{v1.x+v2.x, v1.y+v2.y}; 13 | 14 | add_inplace :: (v1: &V2, v2: V2) { 15 | v1.x += v2.x; 16 | v1.y += v2.y; 17 | } 18 | 19 | format :: (output: &conv.Format_Output, _: &conv.Format, v: &V2) { 20 | conv.format(output, "({}, {})", v.x, v.y); 21 | } 22 | } 23 | 24 | main :: () { 25 | { 26 | // L-Values 27 | 28 | v := V2.{1, 2}; 29 | println(v->add(.{3, 4})); 30 | 31 | 32 | v->add_inplace(.{3, 4}); 33 | println(v); 34 | } 35 | 36 | { 37 | // R-Value 38 | out := (V2.{1, 2})->add(.{3, 4}); 39 | println(out); 40 | 41 | // This does work because you can take the address of a struct literal. 42 | // However, there is no way to retrieve the value of the sturct literal 43 | // after this operation, so nothing can be printed. 44 | (V2.{1, 2})->add_inplace(.{3, 4}); 45 | } 46 | } -------------------------------------------------------------------------------- /tests/auto_poly: -------------------------------------------------------------------------------- 1 | i32 2 | i32 3 | Map(i32, [] u8) 4 | Vector2(i32) { x = 1, y = 1 } 5 | i32 to [] u8 6 | 1234 7 | WOOT WOOT!!! 8 | type of thing is &Thing(f32) 9 | thing is Thing(f32) { value = 0.0000 } 10 | 0 11 | 2 12 | 4 13 | 6 14 | 8 15 | 10 16 | -------------------------------------------------------------------------------- /tests/auto_poly.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | dumb :: (it: Iterator, m: &Map) { 6 | println(it.Iter_Type); 7 | println(__autopoly_var_0); 8 | println(typeof *m); 9 | } 10 | 11 | Vector2 :: struct (T: type_expr) { 12 | x, y: T; 13 | } 14 | 15 | vec_add :: (v1: Vector2, v2: typeof v1) => (typeof v1).{ v1.x + v2.x, v1.y + v2.y }; 16 | 17 | mappable :: (k: m.Key_Type, m: &Map, x: $T) { 18 | printf("{} to {}\n", m.Key_Type, m.Value_Type); 19 | println(k); 20 | println(x); 21 | } 22 | 23 | Thing :: struct (type: type_expr) { 24 | value: type; 25 | } 26 | 27 | f :: (thing: &Thing, other: typeof thing) { 28 | printf("type of thing is {}\n", typeof thing); 29 | printf("thing is {}\n", *thing); 30 | } 31 | 32 | main :: (args) => { 33 | m: Map(i32, str); 34 | dumb(iter.as_iter(1 .. 10), &m); 35 | 36 | V :: Vector2(i32) 37 | v1 := V.{ 1, 0 }; 38 | v2 := V.{ 0, 1 }; 39 | println(vec_add(v1, v2)); 40 | 41 | mappable(1234, &m, "WOOT WOOT!!!"); 42 | 43 | t: Thing(f32); 44 | f(&t, &t); 45 | 46 | for iter.as_iter(0 .. 100) |> iter.map(x => x * 2) |> iter.filter(x => x <= 10) { 47 | println(it); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/avl_test: -------------------------------------------------------------------------------- 1 | 8[3] ( 5[1] ( 0[0] _ ) 20[2] ( 15[1] ( 10[0] _ ) 25[0] ) ) 2 | Contains 7? false 3 | Contains 15? true 4 | Contains 0? true 5 | -------------------------------------------------------------------------------- /tests/avl_test.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: () { 6 | tree: &avl_tree.AVL_Tree(i32); 7 | 8 | avl_tree.insert(&tree, 20); 9 | avl_tree.insert(&tree, 5); 10 | avl_tree.insert(&tree, 8); 11 | avl_tree.insert(&tree, 25); 12 | avl_tree.insert(&tree, 0); 13 | avl_tree.insert(&tree, 15); 14 | avl_tree.insert(&tree, 10); 15 | 16 | avl_tree.print(tree); 17 | print("\n"); 18 | 19 | printf("Contains {}? {}\n", 7, avl_tree.contains(tree, 7)); 20 | printf("Contains {}? {}\n", 15, avl_tree.contains(tree, 15)); 21 | printf("Contains {}? {}\n", 0, avl_tree.contains(tree, 0)); 22 | } -------------------------------------------------------------------------------- /tests/baked_parameters: -------------------------------------------------------------------------------- 1 | 0 1 2 3 4 2 | 0 1 2 3 4 5 6 7 8 9 3 | 0 1 2 3 4 5 6 7 8 9 4 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 5 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 6 | 1234 7 | 1234 8 | 1234 9 | 1234 10 | 1234 11 | 1234 12 | 1234 13 | 1234 14 | 1234 15 | 1234 16 | Dwight's age is 32. 17 | Jim's age is 25. 18 | Pam's age is 24. 19 | Michael's age is 0. 20 | -------------------------------------------------------------------------------- /tests/baked_parameters.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | count_to :: ($N: i32) { 6 | for i in 0 .. N do printf("{} ", i); 7 | print("\n"); 8 | } 9 | 10 | alloc_slice :: ($T: type_expr, N: i32) -> [] T { 11 | data := cast([&] T) calloc(sizeof T * N); 12 | return .{ data, N }; 13 | } 14 | 15 | count_to_30 :: #solidify count_to { N = 30 }; 16 | 17 | main :: (args: [] cstr) { 18 | count_to(5); 19 | count_to(10); 20 | count_to(10); 21 | count_to_30(); 22 | 23 | // This counts as a compile-time known value. 24 | UP_TO :: 100; 25 | count_to(UP_TO); 26 | 27 | sl := alloc_slice(i32, 10); 28 | for & sl do *it = 1234; 29 | 30 | for sl do println(it); 31 | 32 | 33 | // This is so much cleaner than the alternative. 34 | ages := map.make(str, u32); 35 | defer delete(&ages); 36 | 37 | map.put(&ages, "Dwight", 32); 38 | map.put(&ages, "Jim", 25); 39 | map.put(&ages, "Pam", 24); 40 | 41 | print_age :: (ages: &map.Map(str, u32), name: str) { 42 | age := map.get(ages, name) ?? 0; 43 | printf("{}'s age is {}.\n", name, age); 44 | } 45 | 46 | print_age(&ages, "Dwight"); 47 | print_age(&ages, "Jim"); 48 | print_age(&ages, "Pam"); 49 | print_age(&ages, "Michael"); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /tests/better_field_accesses: -------------------------------------------------------------------------------- 1 | 12 2 | Foo bar 3 | 10 4 | 42 5 | Worked! 6 | -------------------------------------------------------------------------------- /tests/better_field_accesses.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | Foo :: struct { 6 | x, y: i32; 7 | name: str; 8 | age: i32; 9 | } 10 | 11 | get_foo :: () -> Foo { 12 | return .{ 13 | x = 10, y = 20, 14 | name = "Foo bar", 15 | age = 42, 16 | }; 17 | } 18 | 19 | main :: (args: [] cstr) { 20 | printf("{}\n", "Hello World!".count); 21 | 22 | println(get_foo().name); 23 | println(get_foo().x); 24 | println(get_foo().age); 25 | 26 | println((Foo.{ 0, 0, "Worked!", 0 }).name); 27 | } 28 | -------------------------------------------------------------------------------- /tests/bucket_array: -------------------------------------------------------------------------------- 1 | ba[10] is 10. 2 | [0] -> 0 3 | [1] -> 1 4 | [2] -> 2 5 | [3] -> 3 6 | [0] -> 4 7 | [1] -> 5 8 | [2] -> 6 9 | [3] -> 7 10 | [0] -> 8 11 | [1] -> 9 12 | [2] -> 10 13 | [3] -> 11 14 | [0] -> 12 15 | [1] -> 13 16 | [2] -> 14 17 | [3] -> 15 18 | [0] -> 16 19 | [1] -> 17 20 | [2] -> 18 21 | [3] -> 19 22 | [0] -> 20 23 | [1] -> 21 24 | [2] -> 22 25 | [3] -> 23 26 | 0 27 | 1 28 | 2 29 | 3 30 | 4 31 | 5 32 | 6 33 | 7 34 | 8 35 | 9 36 | 10 37 | 11 38 | 12 39 | 13 40 | 14 41 | 15 42 | 16 43 | 17 44 | 18 45 | 19 46 | 20 47 | 21 48 | 22 49 | 23 50 | Sum is 276 51 | -------------------------------------------------------------------------------- /tests/bucket_array.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | ba := bucket_array.make(i32, 4); 7 | for i in 24 do ba << i; 8 | 9 | printf("ba[10] is {}.\n", ba[10]); 10 | 11 | sum := 0; 12 | bucket_array.for_each(ba, [value] { 13 | printf("[{}] -> {}\n", bucket_index, *value); 14 | sum += *value; 15 | }); 16 | 17 | for it in bucket_array.as_iter(&ba) { 18 | printf("{}\n", it); 19 | } 20 | 21 | printf("Sum is {}\n", sum); 22 | } 23 | -------------------------------------------------------------------------------- /tests/bugs/anonymous_struct_defaults: -------------------------------------------------------------------------------- 1 | S { 2 | some_array = [ 3 | { 4 | name = "Joe", 5 | age = 14 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /tests/bugs/anonymous_struct_defaults.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | S :: struct { 6 | some_array: [..] struct { 7 | name : str = "Default"; 8 | age : i32 = 43; 9 | }; 10 | } 11 | 12 | main :: (args) => { 13 | v: S; 14 | array.init(&v.some_array); 15 | 16 | do_something_with_S(&v); 17 | 18 | printf("{*p}\n", &v); 19 | } 20 | 21 | do_something_with_S :: (s: &S) { 22 | s.some_array << .{ "Joe", 14 }; 23 | } 24 | -------------------------------------------------------------------------------- /tests/bugs/array_lengths: -------------------------------------------------------------------------------- 1 | true 2 | true 3 | true 4 | true 5 | -------------------------------------------------------------------------------- /tests/bugs/array_lengths.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core { * } 4 | 5 | An_Enum :: enum { 6 | A; 7 | B; 8 | C; 9 | D; 10 | 11 | Count; 12 | } 13 | 14 | A_Struct :: struct { 15 | a: i32; 16 | b: i32; 17 | c: i32; 18 | } 19 | 20 | main :: () { 21 | arr1: [cast(i32)(3 * 4 - 5)]f32; 22 | arr2: [cast(i32)An_Enum.Count]A_Struct; 23 | 24 | println(arr1.count == (3 * 4 - 5)); 25 | println(sizeof(typeof(arr1)) == (3 * 4 - 5) * sizeof(f32)); 26 | 27 | println(arr2.count == ~~An_Enum.Count); 28 | println(sizeof(typeof(arr2)) == ~~An_Enum.Count * sizeof(A_Struct)); 29 | } 30 | -------------------------------------------------------------------------------- /tests/bugs/autopoly_limits: -------------------------------------------------------------------------------- 1 | (123, 456.0000) 2 | -------------------------------------------------------------------------------- /tests/bugs/autopoly_limits.onyx: -------------------------------------------------------------------------------- 1 | use core {package, *} 2 | 3 | f :: ctx => { 4 | x, y := 123, 456.0f; 5 | if ctx.a > 0 { 6 | return Pair.make(x, y), false; 7 | } 8 | 9 | return .{}, true; 10 | } 11 | 12 | g :: (c: $Ctx, f: (Ctx) -> ($T, bool)) -> T { 13 | t, _ := f(c); 14 | return t; 15 | } 16 | 17 | main :: () { 18 | p := g(.{a = 10}, f); 19 | printf("{}\n", p); 20 | } 21 | -------------------------------------------------------------------------------- /tests/bugs/defer_block_in_macro: -------------------------------------------------------------------------------- 1 | main took 1000 milliseconds. 1010 10 2 | Deferred. 3 | -------------------------------------------------------------------------------- /tests/bugs/defer_block_in_macro.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | test_macro :: macro () { 6 | defer { 7 | println("Deferred."); 8 | } 9 | } 10 | 11 | time_block :: macro (name: str) { 12 | start := 10; 13 | defer { 14 | end := 1010; 15 | printf("{} took {} milliseconds. {} {}\n", name, end - start, end, start); 16 | } 17 | } 18 | 19 | main :: (args) => { 20 | test_macro(); 21 | time_block("main"); 22 | } 23 | -------------------------------------------------------------------------------- /tests/bugs/double_polymorph_yield_error: -------------------------------------------------------------------------------- 1 | 5 2 | false 3 | bool 4 | -------------------------------------------------------------------------------- /tests/bugs/double_polymorph_yield_error.onyx: -------------------------------------------------------------------------------- 1 | use core {package, *} 2 | 3 | q :: (v: &$C, g: (&C) -> $T) { 4 | println(*v); 5 | println(g(v)); 6 | println(T); 7 | } 8 | 9 | main :: () { 10 | v := 5; 11 | 12 | q(&v, _ => false); 13 | } 14 | -------------------------------------------------------------------------------- /tests/bugs/fallthrough_defer_interaction: -------------------------------------------------------------------------------- 1 | 1234 2 | World 3 | 1234 4 | World 5 | 1234 6 | World 7 | 1234 8 | World 9 | 1234 10 | World 11 | Closing the iterator 12 | Default case 13 | -------------------------------------------------------------------------------- /tests/bugs/fallthrough_defer_interaction.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | custom_iterator :: () -> Iterator(i32) { 6 | 7 | next :: (data: rawptr) -> (i32, bool) { 8 | return 1234, true; 9 | } 10 | 11 | close :: (data: rawptr) { 12 | println("Closing the iterator"); 13 | } 14 | 15 | return .{ 16 | data = null, 17 | next = next, 18 | close = close, 19 | }; 20 | } 21 | 22 | main :: (args: [] cstr) { 23 | 24 | switch 10 { 25 | case 5 do println("Never"); 26 | 27 | case 10 { 28 | count := 5; 29 | for i in custom_iterator() { 30 | println(i); 31 | defer println("World"); 32 | 33 | count -= 1; 34 | 35 | // :FIXEDBUG This was were it was breaking; the iterator close didn't run here. 36 | if count == 0 do fallthrough; 37 | } 38 | } 39 | 40 | case #default { 41 | println("Default case"); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /tests/bugs/format_negative_other_base: -------------------------------------------------------------------------------- 1 | -4660 2 | -1234 3 | -2844 4 | -------------------------------------------------------------------------------- /tests/bugs/format_negative_other_base.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | use core 4 | 5 | main :: () { 6 | a: i32 = -0x1234; 7 | 8 | core.printf("{}\n", a); 9 | core.printf("{x}\n", a); 10 | core.printf("{b12}\n", a); 11 | } 12 | -------------------------------------------------------------------------------- /tests/bugs/injecting_global_symbol_order: -------------------------------------------------------------------------------- 1 | 2 2 | 3 3 | 4 4 | 5 5 | 6 6 | 7 7 | 8 8 | 9 9 | 11 10 | 13 11 | -------------------------------------------------------------------------------- /tests/bugs/injecting_global_symbol_order.onyx: -------------------------------------------------------------------------------- 1 | use core { 2 | array, 3 | iter, 4 | math, 5 | println 6 | } 7 | 8 | isPrime :: (n: i64) => { 9 | max := math.sqrt(n); 10 | 11 | for x in iter.range(cast(u64, 2), max) { 12 | if n % x == 0 { 13 | return false; 14 | } 15 | } 16 | 17 | return true; 18 | } 19 | 20 | prime_generator :: () => iter.counter(2, i64)->filter(isPrime) 21 | 22 | #inject iter { 23 | range :: (min: $T, max: T) => 24 | iter.counter(min, T)->take_while((x, [max]) => x < max) 25 | } 26 | 27 | main :: () { 28 | for prime in prime_generator() |> iter.take(10) { 29 | println(prime); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/bugs/macro_auto_return_not_resolved: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /tests/bugs/macro_auto_return_not_resolved.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | Point :: struct { x, y: i32; } 6 | 7 | #match hash.to_u32 macro (p: Point) -> #auto do return p.x * 1000 + p.y; 8 | 9 | #operator == macro (p1: Point, p2: Point) -> #auto { 10 | return p1.x == p2.x && p1.y == p2.y; 11 | } 12 | 13 | main :: (args) => { 14 | S := set.make(Point); 15 | 16 | S << Point.{ 1, 2 }; 17 | S << Point.{ 2, 3 }; 18 | S << Point.{ 1, 2 }; 19 | 20 | set.has(&S, Point.{ 1, 2 }) |> println(); 21 | } 22 | -------------------------------------------------------------------------------- /tests/bugs/method_call_source_double: -------------------------------------------------------------------------------- 1 | Made foo! 2 | FOOOO!!! 3 | 1234 4 | FOOOO!!! 5 | 5678 6 | -------------------------------------------------------------------------------- /tests/bugs/method_call_source_double.onyx: -------------------------------------------------------------------------------- 1 | use core {package, *} 2 | 3 | Foo :: struct { 4 | use vtable: &VTable; 5 | x: u32; 6 | 7 | VTable :: struct { 8 | f: (&Foo) -> void; 9 | } 10 | } 11 | 12 | good_foo := Foo.VTable.{ 13 | f = (f) => { 14 | println("FOOOO!!!"); 15 | println(f.x); 16 | } 17 | } 18 | 19 | make_foo :: () -> &Foo { 20 | foo := new(Foo); 21 | foo.vtable = &good_foo; 22 | foo.x = 1234; 23 | 24 | printf("Made foo!\n"); 25 | return foo; 26 | } 27 | 28 | main :: () { 29 | make_foo()->f(); 30 | 31 | (Foo.{&good_foo, 5678})->f(); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /tests/bugs/namespace_aliasing: -------------------------------------------------------------------------------- 1 | Aliasing is working 2 | Aliasing is working 3 | -------------------------------------------------------------------------------- /tests/bugs/namespace_aliasing.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | use core {*} 3 | 4 | SomeNamespace :: struct { 5 | foo :: () { 6 | println("Aliasing is working"); 7 | } 8 | } 9 | 10 | main :: (args) => { 11 | { 12 | SN :: SomeNamespace 13 | 14 | SN.foo(); 15 | } 16 | 17 | { 18 | // This is no longer a feature, and cannot be used anymore 19 | // use SomeNamespace; 20 | 21 | SomeNamespace.foo(); 22 | } 23 | } -------------------------------------------------------------------------------- /tests/bugs/print_formatters: -------------------------------------------------------------------------------- 1 | { 2 | Hello{}World 3 | Hello{}World 4 | }{hello}{ 5 | }3R{ 6 | -------------------------------------------------------------------------------- /tests/bugs/print_formatters.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core {printf} 3 | 4 | main :: () { 5 | printf("{\n"); 6 | printf("Hello{"); 7 | printf("}World\n"); 8 | printf("Hello{{}}World\n"); 9 | printf("}{hello}{\n", 123); 10 | printf("}{b32}{\n", 123); 11 | } -------------------------------------------------------------------------------- /tests/caller_location: -------------------------------------------------------------------------------- 1 | Hello 2 | I was called from caller_location.onyx:12:19 3 | 1234.0000 4 | I was called from caller_location.onyx:13:19 5 | 1234 6 | I was called from caller_location.onyx:24:23 7 | -------------------------------------------------------------------------------- /tests/caller_location.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | using_callsite :: (value: $T, site := #callsite) { 6 | println(value); 7 | path := string.split(site.file, ~~(#char "\\" if runtime.compiler_os == .Windows else #char "/")); 8 | printf("I was called from {}:{}:{}\n", path[path.count - 1], site.line, site.column); 9 | } 10 | 11 | main :: (args: [] cstr) { 12 | using_callsite("Hello"); 13 | using_callsite(1234.0f); 14 | 15 | something := Something.{}; 16 | something->method(); 17 | } 18 | 19 | 20 | Something :: struct { 21 | member := cast(u32) 1234; 22 | 23 | method :: (use s: &Something) { 24 | using_callsite(member); 25 | } 26 | } 27 | 28 | use runtime 29 | -------------------------------------------------------------------------------- /tests/char_literals: -------------------------------------------------------------------------------- 1 | az 2 | r is the 17 of the alphabet. 3 | 4 | Something else 5 | -------------------------------------------------------------------------------- /tests/char_literals.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | 4 | main :: () { 5 | s: dyn_str; 6 | defer string.free(&s); 7 | 8 | string.append(&s, .['a', 'z']); 9 | 10 | println(s); 11 | 12 | 13 | 14 | x := 'r' - 'a'; 15 | printf("{} is the {} of the alphabet.\n", 'r', x); 16 | 17 | a_newline := '\n'; 18 | printf("{}", a_newline); 19 | println("Something else"); 20 | } 21 | -------------------------------------------------------------------------------- /tests/code_block_captures: -------------------------------------------------------------------------------- 1 | 7 2 | foo => 123 3 | leet => 1337 4 | -------------------------------------------------------------------------------- /tests/code_block_captures.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | main :: () { 4 | arr := .[2, 3, 5, 7, 11]; 5 | 6 | x := 5; 7 | 8 | val := slice.find_opt(arr, [n](n > x)); 9 | val->with([captured_name] { 10 | println(captured_name); 11 | }); 12 | 13 | m := Map.literal(str, i32, .[ 14 | .{ "foo", 123 }, 15 | .{ "leet", 1337 } 16 | ]); 17 | 18 | Map.each(m, [k, v] { 19 | printf("{} => {}\n", k, v); 20 | }); 21 | } 22 | 23 | #inject Map { 24 | each :: macro (m: $M, body: Code) { 25 | for& m.entries { 26 | #unquote body(it.key, it.value); 27 | } 28 | } 29 | } 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/compile_time_procedures: -------------------------------------------------------------------------------- 1 | hello world! 2 | 24 3 | 4 4 | 20 5 | true 6 | -------------------------------------------------------------------------------- /tests/compile_time_procedures.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | Test_VTable :: struct { 6 | first : (i32) -> i32; 7 | second : (i32) -> i32; 8 | 9 | third : (i32, i32) -> i32 = null_proc; 10 | } 11 | 12 | test_vtable1 := Test_VTable.{ 13 | first = (a: i32) -> i32 { return a * 2; }, 14 | second = (a: i32) -> i32 { return a + 2; }, 15 | } 16 | 17 | test_vtable2 := Test_VTable.{ 18 | first = (a: i32) -> i32 { return a / 2; }, 19 | second = (a: i32) -> i32 { return a - 2; }, 20 | } 21 | 22 | 23 | Test_Thing :: struct { 24 | vt : &Test_VTable; 25 | 26 | data : i32; 27 | } 28 | 29 | // because of the work i did above, this also works now. 30 | dummy := () { println("hello world!"); } 31 | 32 | 33 | main :: (args: [] cstr) { 34 | dummy(); 35 | 36 | t := Test_Thing.{ &test_vtable1, 10 }; 37 | println(do_a_thing(&t)); 38 | 39 | t.vt = &test_vtable2; 40 | println(do_a_thing(&t)); 41 | 42 | tmp_vt := Test_VTable.{ first = test_vtable1.second, second = test_vtable2.first, third = math.max }; 43 | t.vt = &tmp_vt; 44 | println(do_a_thing(&t)); 45 | 46 | println(t.vt.first == test_vtable1.second); 47 | 48 | do_a_thing :: (use t: &Test_Thing) -> i32 { 49 | if vt.second == null_proc || vt.first == null_proc do return data; 50 | 51 | res := data |> vt.second() |> vt.first(); 52 | if vt.third != null_proc do res = vt.third(res, 20); 53 | 54 | return res; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/complicated_polymorph: -------------------------------------------------------------------------------- 1 | 20 2 | 23.0000 3 | 258.0000 4 | -------------------------------------------------------------------------------- /tests/defer_with_continue: -------------------------------------------------------------------------------- 1 | Doing something with Index is 0 2 | Doing something with Index is 1 3 | Doing something with Index is 2 4 | Skipping 3!! 5 | Index is 3 6 | Doing something with Index is 4 7 | Doing something with Index is 5 8 | Doing something with Index is 6 9 | Doing something with Index is 7 10 | Doing something with Index is 8 11 | Doing something with Index is 9 12 | i is 10 13 | 14 | 15 | =================================== 16 | Doing something with Index is 0 17 | Doing something with Index is 1 18 | Doing something with Index is 2 19 | Skipping 3!! 20 | Index is 3 21 | i is 4 22 | 23 | 24 | =================================== 25 | In block deferred! 26 | Deferred! 27 | Default! 28 | At the end! 29 | -------------------------------------------------------------------------------- /tests/defer_with_continue.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | defer println("At the end!"); 7 | i := 0; 8 | while i < 10 { 9 | defer i += 1; 10 | defer printf("Index is {}\n", i); 11 | 12 | if i == 3 { 13 | printf("Skipping {}!!\n", i); 14 | continue; 15 | } 16 | 17 | print("Doing something with "); 18 | } 19 | printf("i is {}\n", i); 20 | 21 | println("\n\n==================================="); 22 | i = 0; 23 | while i < 10 { 24 | defer i += 1; 25 | defer printf("Index is {}\n", i); 26 | 27 | if i == 3 { 28 | printf("Skipping {}!!\n", i); 29 | break; 30 | } 31 | 32 | print("Doing something with "); 33 | } 34 | printf("i is {}\n", i); 35 | 36 | println("\n\n==================================="); 37 | switch i { 38 | case 4 { 39 | defer println("Deferred!"); 40 | { 41 | defer println("In block deferred!"); 42 | fallthrough; 43 | } 44 | println("Case 4!"); 45 | } 46 | 47 | case #default { 48 | println("Default!"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/defined_test: -------------------------------------------------------------------------------- 1 | true 2 | false 3 | false 4 | -------------------------------------------------------------------------------- /tests/defined_test.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | println(#defined(stdio)); 7 | println(#defined(foobar)); 8 | println(#defined(array.Untyped_Array.foo)); 9 | } 10 | -------------------------------------------------------------------------------- /tests/distinct_types: -------------------------------------------------------------------------------- 1 | MyString[this works] 2 | Some(MyString["an optional works"]) 3 | MyString[an optional works] 4 | MyString[an optional works] 5 | MyString[an optional works] 6 | -------------------------------------------------------------------------------- /tests/distinct_types.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | use core {*} 4 | 5 | MyString :: #distinct str 6 | 7 | main :: () { 8 | x := MyString.{ "this works" }; 9 | 10 | y: ? MyString = MyString.{ "an optional works" }; 11 | 12 | println(x); 13 | println(y); 14 | println(y->unwrap()); 15 | println(y ?? MyString.{"alternate"}); 16 | 17 | z := y ?? x; 18 | printf("{}\n", z); 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/do_block_single_statement: -------------------------------------------------------------------------------- 1 | 1 2 | 10 3 | 10.0000 4 | -------------------------------------------------------------------------------- /tests/do_block_single_statement.onyx: -------------------------------------------------------------------------------- 1 | use core {println} 2 | 3 | main :: () { 4 | // 'x' should be set to 1, but the compiler hangs/crashes. 5 | // removing 'do' has the same issue. 6 | x := do if true { 7 | return 1; 8 | } else { 9 | return 2; 10 | }; 11 | 12 | y := do return 10;; // Needing double ';' is gross here. 13 | 14 | z := do -> f32 return 10;; 15 | 16 | println(x); 17 | println(y); 18 | println(z); 19 | } -------------------------------------------------------------------------------- /tests/dyn_str: -------------------------------------------------------------------------------- 1 | Hello, World! 2 | This is another sentence. 3 | -------------------------------------------------------------------------------- /tests/dyn_str.onyx: -------------------------------------------------------------------------------- 1 | use core.string 2 | use core.conv 3 | use core 4 | 5 | use core { 6 | println 7 | } 8 | 9 | 10 | main :: () { 11 | output: dyn_str; 12 | defer string.free(&output); 13 | 14 | string.append(&output, "Hello"); 15 | string.append(&output, "World"); 16 | string.append(&output, '!'); 17 | 18 | string.insert(&output, 5, ", "); 19 | 20 | println(output); 21 | 22 | 23 | // `conv.format` appends to the dynamic string. Use 24 | // `string.clear` to empty it first. 25 | string.clear(&output); 26 | conv.format(&output, "This is another {}.", "sentence"); 27 | 28 | println(output); 29 | } -------------------------------------------------------------------------------- /tests/first_class_optional: -------------------------------------------------------------------------------- 1 | 0 2 | 30 3 | None 4 | Some(40) 5 | Some(0) 6 | Some(60) 7 | -------------------------------------------------------------------------------- /tests/first_class_optional.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core {println} 3 | 4 | foo :: (x: ?i32) -> i32 { 5 | return x? + 10; 6 | } 7 | 8 | bar :: (x: ?i32) -> ?i32 { 9 | return x? * 2; 10 | } 11 | 12 | main :: () { 13 | println(foo(.{})); 14 | println(foo(20)); 15 | 16 | println(bar(.{})); 17 | println(bar(20)); 18 | 19 | println(bar(foo(.{}))); 20 | println(bar(foo(20))); 21 | } 22 | -------------------------------------------------------------------------------- /tests/float_parsing: -------------------------------------------------------------------------------- 1 | 12.0000 2 | 12.0000 3 | 8.0000 4 | 12.3399 5 | 0.3399 6 | 2.0000 7 | 1.0000 8 | 1.0000 9 | 1.0000 10 | 10000.0000 11 | 0.0010 12 | 0.0002 13 | -5000000.0000 14 | -0.0500 15 | 0.0000 16 | -1000000.0000 17 | 5.0000 18 | 10.0000 19 | 0.0000 20 | 0.0000 21 | 0.0000 22 | 1.0000 23 | -1.0000 24 | 1.0000 25 | 1.0000 26 | 0.0000 27 | 0.0000 28 | 0.0000 29 | -1000000.0000 30 | -------------------------------------------------------------------------------- /tests/float_parsing.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | 7 | // @CoreLibraries // The commented out cases can be re-enabled when f64_to_str is better. 8 | // Right now there is an integer overflow because it converts the float to an i64. 9 | strings := str.[ 10 | /* these should parse fully */ 11 | "12", 12 | "12.0", 13 | "08", /* not octal! */ 14 | "+12.34", 15 | ".34", 16 | "\t \n2.", 17 | "1e0", 18 | "1e+0", 19 | "1e-0", 20 | "1.e4", 21 | ".1e-2", 22 | "2e-4", 23 | "-5e006", 24 | //"-5e+16", 25 | "-.05", 26 | "-.0", 27 | "-1e6", 28 | /* these should parse only the initial part */ 29 | "5c5", 30 | "10ee5", 31 | "0x06", /* not hex! */ 32 | "--1" , 33 | "-+1" , 34 | "1e--4" , 35 | "-1e.4", 36 | "1e 4", 37 | "1e-g", 38 | "", "foobar", /* both 0 */ 39 | " e5", /* also 0 */ 40 | "-1e6", 41 | /* overflow/underflow */ 42 | // "1e500000", 43 | // "1e-500000", 44 | // "-1e500000", 45 | // "-1e-500000", 46 | ]; 47 | 48 | for s in strings { 49 | value := conv.str_to_f64(s); 50 | println(value); 51 | } 52 | } -------------------------------------------------------------------------------- /tests/for_loop_indexes: -------------------------------------------------------------------------------- 1 | 0: 10 2 | 1: 11 3 | 2: 12 4 | 3: 13 5 | 4: 14 6 | 5: 15 7 | 6: 16 8 | 7: 17 9 | 8: 18 10 | 9: 19 11 | 10: 20 12 | 11: 21 13 | 12: 22 14 | 13: 23 15 | 14: 24 16 | 15: 25 17 | 16: 26 18 | 17: 27 19 | 18: 28 20 | 19: 29 21 | 20: 30 22 | 21: 31 23 | 22: 32 24 | 23: 33 25 | 24: 34 26 | 25: 35 27 | 26: 36 28 | 27: 37 29 | 28: 38 30 | 29: 39 31 | 30: 40 32 | 31: 41 33 | 32: 42 34 | 33: 43 35 | 34: 44 36 | 35: 45 37 | 36: 46 38 | 37: 47 39 | 38: 48 40 | 39: 49 41 | 40: 50 42 | 41: 51 43 | 42: 52 44 | 43: 53 45 | 44: 54 46 | 45: 55 47 | 46: 56 48 | 47: 57 49 | 48: 58 50 | 49: 59 51 | 50: 60 52 | 51: 61 53 | 52: 62 54 | 53: 63 55 | 54: 64 56 | 55: 65 57 | 56: 66 58 | 57: 67 59 | 58: 68 60 | 59: 69 61 | 60: 70 62 | 61: 71 63 | 62: 72 64 | 63: 73 65 | 64: 74 66 | 65: 75 67 | 66: 76 68 | 67: 77 69 | 68: 78 70 | 69: 79 71 | 70: 80 72 | 71: 81 73 | 72: 82 74 | 73: 83 75 | 74: 84 76 | 75: 85 77 | 76: 86 78 | 77: 87 79 | 78: 88 80 | 79: 89 81 | 80: 90 82 | 81: 91 83 | 82: 92 84 | 83: 93 85 | 84: 94 86 | 85: 95 87 | 86: 96 88 | 87: 97 89 | 88: 98 90 | 89: 99 91 | (i64) 0: 20 92 | (i64) 1: 21 93 | (i64) 2: 22 94 | (i64) 3: 23 95 | (i64) 4: 24 96 | (i64) 5: 25 97 | (i64) 6: 26 98 | (i64) 7: 27 99 | (i64) 8: 28 100 | (i64) 9: 29 101 | (i64) 10: 30 102 | (i64) 11: 31 103 | (i64) 12: 32 104 | (i64) 13: 33 105 | (i64) 14: 34 106 | (i64) 15: 35 107 | (i64) 16: 36 108 | (i64) 17: 37 109 | (i64) 18: 38 110 | (i64) 19: 39 111 | (i64) 20: 40 112 | (i64) 21: 41 113 | (i64) 22: 42 114 | (i64) 23: 43 115 | (i64) 24: 44 116 | (i64) 25: 45 117 | (i64) 26: 46 118 | (i64) 27: 47 119 | (i64) 28: 48 120 | (i64) 29: 49 121 | 0: 2 122 | 1: 3 123 | 2: 5 124 | 3: 7 125 | 4: 11 126 | -------------------------------------------------------------------------------- /tests/for_loop_indexes.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | main :: () { 4 | for value, index in 10 .. 100 { 5 | // value: 10 -> 99 6 | // index: 0 -> 89 7 | // 8 | // value is i32 9 | // index is i32 10 | printf("{}: {}\n", index, value); 11 | } 12 | 13 | for value, index: i64 in 20 .. 50 { 14 | // value: 20 -> 49 15 | // index: 0 -> 29 16 | // 17 | // value is i32 18 | // index is i64 19 | printf("({}) {}: {}\n", typeof index, index, value); 20 | } 21 | 22 | values := .[2, 3, 5, 7, 11]; 23 | for value: i32, index in values { 24 | printf("{}: {}\n", index, value); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/hello_world: -------------------------------------------------------------------------------- 1 | Hello, World! 2 | -------------------------------------------------------------------------------- /tests/hello_world.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | #load "core/module" 4 | 5 | use core {*} 6 | 7 | main :: (args: [] cstr) { 8 | println("Hello, World!"); 9 | } 10 | -------------------------------------------------------------------------------- /tests/hex_autocoder: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog 2 | 54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67 3 | The quick brown fox jumps over the lazy dog 4 | -------------------------------------------------------------------------------- /tests/hex_autocoder.onyx: -------------------------------------------------------------------------------- 1 | 2 | use core {*} 3 | 4 | main :: () { 5 | s := "The quick brown fox jumps over the lazy dog"; 6 | println(s); 7 | 8 | encoded := encoding.hex.encode(s); 9 | println(encoded); 10 | 11 | decoded := encoding.hex.decode(encoded); 12 | println(decoded); 13 | } 14 | -------------------------------------------------------------------------------- /tests/i32map: -------------------------------------------------------------------------------- 1 | true 2 | false 3 | Hello World! 4 | { 5 | 50 => "Hello " 6 | 1234 => "World!" 7 | } 8 | false 9 | false 10 | Freeing map 11 | -------------------------------------------------------------------------------- /tests/i32map.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | #load "core/module" 4 | 5 | use core {*} 6 | 7 | main :: (args: [] cstr) { 8 | imap : Map(i32, str); 9 | map.init(&imap); 10 | defer { 11 | print("Freeing map\n"); 12 | map.free(&imap); 13 | } 14 | map.put(&imap, 50, "Hello "); 15 | imap->put(1234, "World!"); 16 | 17 | println(map.has(&imap, 50)); 18 | println(map.has(&imap, 51)); 19 | 20 | printf("{}{}\n", map.get(&imap, 50)->unwrap(), map.get(&imap, 1234)->unwrap()); 21 | 22 | printf("{*p}\n", &imap); 23 | 24 | map.delete(&imap, 50); 25 | println(map.has(&imap, 50)); 26 | 27 | map.clear(&imap); 28 | println(map.has(&imap, 1234)); 29 | } 30 | -------------------------------------------------------------------------------- /tests/if_expressions: -------------------------------------------------------------------------------- 1 | 5678.0000 2 | True 3 | 20 4 | V2 { x = 10.0000, y = 20.0000 } 5 | -------------------------------------------------------------------------------- /tests/if_expressions.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {package, println, printf} 4 | 5 | some_function :: () -> f32 { 6 | println("In some function!"); 7 | return 1234; 8 | } 9 | 10 | new_max :: (a: $T, b: T) -> T { 11 | // Much much better! 12 | return a if a > b else b; 13 | } 14 | 15 | V2 :: struct { x, y: f32; } 16 | 17 | main :: (args: [] cstr) { 18 | 19 | condition := 12 > 34; 20 | 21 | x := some_function() if condition else 5678.0f; 22 | println(x); 23 | 24 | println("True" if x > 5000 else "False" if false else "REALLY FALSE"); 25 | 26 | println(new_max(10, 20)); 27 | 28 | v: V2 = (.{ 10, 20 }) if true else .{ 30, 40 }; 29 | printf("{}\n", v); 30 | } 31 | -------------------------------------------------------------------------------- /tests/ignored_return_values: -------------------------------------------------------------------------------- 1 | hello 2 | 123 3 | Str: hello 4 | 12 5 | 13 6 | -------------------------------------------------------------------------------- /tests/ignored_return_values.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | 3 | foo :: () -> (str, i32, bool, Allocator) { 4 | return "hello", 123, false, .{}; 5 | } 6 | 7 | takes_str :: (s: str) { 8 | core.printf("Str: {}\n", s); 9 | } 10 | 11 | Foo :: struct { 12 | x, y: i32; 13 | m: str; 14 | } 15 | 16 | #inject Foo { 17 | method :: (f: ^Foo) -> (i32, i32, str) { 18 | return f.x, f.y, f.m; 19 | } 20 | } 21 | 22 | main :: () { 23 | m, n := foo(); 24 | core.println(m); 25 | core.println(n); 26 | 27 | takes_str(foo()); 28 | 29 | f := Foo.{ 12, 34, "Working!" }; 30 | x := f->method(); 31 | core.println(x); 32 | 33 | y := 1; 34 | core.println(y + Foo.method(^f)); 35 | } 36 | -------------------------------------------------------------------------------- /tests/implicit_initialize_locals: -------------------------------------------------------------------------------- 1 | data: 0x0 count: 0 2 | data: 0x100 count: 100 3 | Untyped_Array { 4 | data = (null), 5 | count = 0, 6 | capacity = 0, 7 | allocator = Allocator { 8 | data = (null), 9 | func = func[0] 10 | } 11 | } 12 | [ 13 | Map.Entry([] u8, i32) { 14 | next = -1, 15 | hash = 193461347, 16 | key = "Joe", 17 | value = 12 18 | }, 19 | Map.Entry([] u8, i32) { 20 | next = 0, 21 | hash = 2089242307, 22 | key = "Jane", 23 | value = 34 24 | } 25 | ] 26 | -------------------------------------------------------------------------------- /tests/implicit_initialize_locals.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args) => { 6 | { 7 | x: [] i32; 8 | printf("data: {} count: {}\n", x.data, x.count); 9 | 10 | y := ([] i32).{ ~~ 0x100, 100 }; 11 | printf("data: {} count: {}\n", y.data, y.count); 12 | } 13 | 14 | { 15 | arr: [..] i32; 16 | printf("{*p}\n", cast(&array.Untyped_Array) &arr); 17 | 18 | people: Map(str, i32); 19 | people["Joe"] = 12; 20 | people["Jane"] = 34; 21 | printf("{*p}\n", &people.entries); 22 | } 23 | } -------------------------------------------------------------------------------- /tests/init_procedures: -------------------------------------------------------------------------------- 1 | In another #init proc. 2 | In an #init proc. 3 | In main! 4 | -------------------------------------------------------------------------------- /tests/init_procedures.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | first_init :: #init #after second_init () { 6 | println("In an #init proc."); 7 | } 8 | 9 | second_init :: #init () { 10 | println("In another #init proc."); 11 | } 12 | 13 | main :: (_) => { 14 | println("In main!"); 15 | } 16 | -------------------------------------------------------------------------------- /tests/interface_scopes: -------------------------------------------------------------------------------- 1 | Woof! Message 1 2 | Woof! Another message! 3 | Woof! Such cool message! 4 | WOOF! YELL THIS. 5 | Meow! Message 1 6 | Meow! Another message! 7 | Meow! Such cool message! 8 | MEOW! Yell this. 9 | -------------------------------------------------------------------------------- /tests/interface_scopes.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | Speak :: interface (T: type_expr) { 4 | t as T; 5 | 6 | { speak(t, str.{}) } -> void; 7 | { yell(t, str.{}) } -> void; 8 | 9 | speak :: #match {} 10 | } 11 | 12 | #inject Speak { 13 | yell :: #match {} 14 | } 15 | 16 | Dog :: struct {_: i32} 17 | 18 | #overload 19 | Speak.speak :: (d: Dog, msg: str) { 20 | printf("Woof! {}\n", msg); 21 | } 22 | 23 | #overload 24 | Speak.yell :: (d: Dog, msg: str) { 25 | printf("WOOF! {}\n", string.temp_copy(msg) |> string.to_uppercase()); 26 | } 27 | 28 | Cat :: struct {_: i32} 29 | 30 | #overload 31 | Speak.speak :: (d: Cat, msg: str) { 32 | printf("Meow! {}\n", msg); 33 | } 34 | 35 | #overload 36 | Speak.yell :: (d: Cat, msg: str) { 37 | printf("MEOW! {}\n", msg); 38 | } 39 | 40 | 41 | speak_things :: (thing: $T/Speak) { 42 | Speak.speak(thing, "Message 1"); 43 | Speak.speak(thing, "Another message!"); 44 | Speak.speak(thing, "Such cool message!"); 45 | 46 | Speak.yell(thing, "Yell this."); 47 | } 48 | 49 | 50 | main :: () { 51 | dog := Dog.{}; 52 | cat := Cat.{}; 53 | 54 | speak_things(dog); 55 | speak_things(cat); 56 | } 57 | -------------------------------------------------------------------------------- /tests/interfaces: -------------------------------------------------------------------------------- 1 | -1500840774 2 | OnyxContext is not hashable! 3 | Allocator is not hashable! 4 | 19 5 | -460.00 + 1060.00i 6 | 7 7 | [ 4.0000, 2.0000, 4.0000, 7.0000, 4.0000 ] 8 | [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 9 | true 10 | false 11 | true 12 | false 13 | true 14 | [ 1, 2, 3, 4, 5 ] 15 | -------------------------------------------------------------------------------- /tests/json_test: -------------------------------------------------------------------------------- 1 | [ { foo = 1 }, { foo = 2 } ] 2 | [{"x":1},{"x":2}] 3 | 1 4 | {"test":"Wow!","working":123,"data":[1,2,3,4,5],"people":[{"name":"Joe"},{"name":"Bob"}],"other":[{"x":1},{"x":2}]} 5 | {"foo":{"data":5}} 6 | 🂡 7 | main.Union_Test { v1 = None, v2 = Some(123) } 8 | {"v1":null,"v2":123} 9 | {"v1":null,"v2":123} 10 | [ { foo = 1 }, { foo = 2 } ] 11 | -------------------------------------------------------------------------------- /tests/lazy_iterators: -------------------------------------------------------------------------------- 1 | 54.0000 2 | 56.0000 3 | 58.0000 4 | 60.0000 5 | 62.0000 6 | Closing the count iterator... 7 | Starting the iteration... 8 | 54 9 | 56 10 | 58 11 | 60 12 | 62 13 | Closing the count iterator... 14 | 58 15 | 16 | Starting the zipped iteration... 17 | 54 42.0000 18 | 56 42.0000 19 | 58 42.0000 20 | 60 42.0000 21 | 62 42.0000 22 | Closing the count iterator... 23 | -------------------------------------------------------------------------------- /tests/left_to_right_order: -------------------------------------------------------------------------------- 1 | 3 == 3 2 | -------------------------------------------------------------------------------- /tests/left_to_right_order.onyx: -------------------------------------------------------------------------------- 1 | 2 | use core {*} 3 | 4 | main :: () { 5 | a := 1; 6 | b := a + do { a += 1; return a; }; 7 | printf("{} == 3\n", b); 8 | } 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/linked_lists: -------------------------------------------------------------------------------- 1 | 4 2 | 1 3 | 5.0000 4 | 1.0000 5 | 2.0000 6 | 3.0000 7 | -------------------------------------------------------------------------------- /tests/linked_lists.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core.list 3 | 4 | use core {println} 5 | 6 | main :: () { 7 | l := list.make(i32); 8 | 9 | l->push_end(1); 10 | l->push_end(2); 11 | l->push_end(3); 12 | l->push_end(4); 13 | l->push_begin(5); 14 | l->push_begin(6); 15 | l->pop_end(); 16 | l->pop_begin(); 17 | 18 | println(l->count()); 19 | println(*(l->at(1))); 20 | 21 | float_list := l->map(x => cast(f32) x); 22 | 23 | for float_list->as_iter() { 24 | println(it); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/lists_comprehensive: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 6 | 5 7 | 6 8 | 7 9 | 8 10 | 9 11 | ================= 12 | Some(0) 13 | Some(1) 14 | Some(2) 15 | Some(3) 16 | Some(4) 17 | ================= 18 | 5 19 | 6 20 | 7 21 | 8 22 | 9 23 | ================= 24 | Some(9) 25 | Some(8) 26 | Some(7) 27 | Some(6) 28 | Some(5) 29 | ================= 30 | None 31 | None 32 | None 33 | None 34 | None 35 | 0 36 | true 37 | -------------------------------------------------------------------------------- /tests/lists_comprehensive.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | main :: () { 4 | l := make(list.List(i32)); 5 | 6 | for 10 { 7 | list.push_end(&l, it); 8 | } 9 | 10 | for iter.as_iter(&l) { 11 | println(it); 12 | } 13 | 14 | println("================="); 15 | for 5 { 16 | list.pop_begin_opt(&l) |> println(); 17 | } 18 | 19 | println("================="); 20 | for iter.as_iter(&l) { 21 | println(it); 22 | } 23 | 24 | println("================="); 25 | for 5 { 26 | list.pop_end_opt(&l) |> println(); 27 | } 28 | 29 | println("================="); 30 | for 5 { 31 | list.pop_begin_opt(&l) |> println(); 32 | } 33 | 34 | println(list.count(&l)); 35 | println(list.empty(&l)); 36 | } 37 | -------------------------------------------------------------------------------- /tests/map_enum_key: -------------------------------------------------------------------------------- 1 | { Apple => "This is apple.", Banana => "This is banana.", Orange => "This is orange." } 2 | { Apple => "This is apple 64.", Banana => "This is banana 64.", Orange => "This is orange 64." } 3 | -------------------------------------------------------------------------------- /tests/map_enum_key.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | use core {*} 4 | 5 | Fruit :: enum { 6 | Apple; 7 | Banana; 8 | Orange; 9 | } 10 | 11 | Fruit_64 :: enum (i64) { 12 | Apple; 13 | Banana; 14 | Orange; 15 | } 16 | 17 | main :: () { 18 | m := make(Map(Fruit, str)); 19 | 20 | m->put(.Apple, "This is apple."); 21 | m->put(.Banana, "This is banana."); 22 | m->put(.Orange, "This is orange."); 23 | 24 | println(m); 25 | 26 | m2 := make(Map(Fruit, str)); 27 | 28 | m2->put(.Apple, "This is apple 64."); 29 | m2->put(.Banana, "This is banana 64."); 30 | m2->put(.Orange, "This is orange 64."); 31 | 32 | println(m2); 33 | } 34 | -------------------------------------------------------------------------------- /tests/multiple_returns_robustness: -------------------------------------------------------------------------------- 1 | 60 2 | 50 3 | 110 4 | -10 to 200 5 | 0 1 2 6 | 3.0000 4.0000 5.0000 7 | -------------------------------------------------------------------------------- /tests/multiple_returns_robustness.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {package, *} 4 | 5 | foo :: () -> (i32, i32) { 6 | return 50, 60; 7 | } 8 | 9 | something :: (f: () -> ($T, T)) -> T { 10 | a, b := f(); 11 | return a + b; 12 | } 13 | 14 | get_extrema :: (arr: [$N] $T) -> (T, T) { 15 | min := arr[0]; 16 | max := arr[0]; 17 | 18 | for e in arr { 19 | if e < min do min = e; 20 | if e > max do max = e; 21 | } 22 | 23 | return min, max; 24 | } 25 | 26 | return_multiple_arrays :: () -> ([3] i32, [3] f32) { 27 | iarr := i32.[ 0, 1, 2 ]; 28 | farr := f32.[ 3, 4, 5 ]; 29 | return iarr, farr; 30 | } 31 | 32 | main :: (args: [] cstr) { 33 | a, b := foo(); 34 | a, b = b, a; 35 | 36 | c := something(foo); 37 | 38 | println(a); 39 | println(b); 40 | println(c); 41 | 42 | 43 | least, greatest := get_extrema(i32.[ -5, 20, 5, -10, 200, 8 ]); 44 | printf("{} to {}\n", least, greatest); 45 | 46 | iarr, farr := return_multiple_arrays(); 47 | array_print(iarr); 48 | array_print(farr); 49 | 50 | array_print :: (arr: [$N] $T) { 51 | for &e in arr { 52 | print(*e); 53 | print(" "); 54 | } 55 | 56 | print("\n"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/named_arguments_test: -------------------------------------------------------------------------------- 1 | x is 10 2 | y is 20.0000 3 | x is 20 4 | y is 10.0000 5 | 6 | 7 | ========================= 8 | 10 9 | [ 10, 20, 30 ] 10 | 10.0000 11 | [ 10.0000, 20.0000, 30.0000 ] 12 | 13 | 14 | ========================= 15 | MATCHED Y: [ 10, 20 ] 16 | MATCHED X: 10 17 | MATCHED Z: 10 18 | 19 | 20 | ========================= 21 | 10 22 | 20 23 | 30.0000 40.0000 50.0000 24 | 25 | 26 | ========================= 27 | false true false true true false true 28 | true false false true true false true 29 | MATCHED X 30 | MATCHED Y 31 | MATCHED Z [ 10, 40, 90 ] 32 | -------------------------------------------------------------------------------- /tests/nested-if-exprs: -------------------------------------------------------------------------------- 1 | cmp(1, 2): -1 2 | cmp(2, 2): 0 3 | cmp(3, 2): 1 4 | -------------------------------------------------------------------------------- /tests/nested-if-exprs.onyx: -------------------------------------------------------------------------------- 1 | use core {printf} 2 | 3 | main :: () { 4 | printf("cmp(1, 2): {}\n", cmp(1, 2)); 5 | printf("cmp(2, 2): {}\n", cmp(2, 2)); 6 | printf("cmp(3, 2): {}\n", cmp(3, 2)); 7 | } 8 | 9 | cmp :: (a: i32, b: i32) -> i32 { 10 | return 0 if a == b else -1 if a < b else 1; 11 | } -------------------------------------------------------------------------------- /tests/nested_array_literals: -------------------------------------------------------------------------------- 1 | [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 2 | [ [ 0, 1, 2, 3 ], [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ] ] 3 | -------------------------------------------------------------------------------- /tests/nested_array_literals.onyx: -------------------------------------------------------------------------------- 1 | 2 | use core {*} 3 | 4 | main :: () { 5 | x := ([3] i32).[ 6 | .[1, 2, 3], 7 | .[4, 5, 6], 8 | .[7, 8, 9] 9 | ]; 10 | 11 | printf("{}\n", x); 12 | 13 | takes_a_nested_array(([4] i32).[ 14 | .[ 0, 1, 2, 3 ], 15 | .[ 1, 2, 3, 4 ], 16 | .[ 2, 3, 4, 5 ], 17 | ]); 18 | } 19 | 20 | takes_a_nested_array :: (arr: [3] [4] i32) { 21 | println(arr); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /tests/new_printf: -------------------------------------------------------------------------------- 1 | 123 Test {} false 12.3 12.34567 [..] Map(i32, [] u8) 2 | -------------------------------------------------------------------------------- /tests/new_printf.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {printf, map} 4 | 5 | main :: (args: [] cstr) { 6 | printf("{} {} {{}} {} {.1} {.5} {}\n", 123, "Test", false, 12.34, 12.3456789, [..] map.Map(i32, str)); 7 | } 8 | -------------------------------------------------------------------------------- /tests/new_struct_behaviour: -------------------------------------------------------------------------------- 1 | Got a value! 2 | Got a value! 3 | 1237 4 | 1235 5 | 11 6 | 219 7 | Joe is 30. 8 | Function 3 9 | Function 2 10 | Function 1 11 | Function 4 12 | V3(4.0000, 9.0000, 16.0000) 13 | -------------------------------------------------------------------------------- /tests/no_types.onyx: -------------------------------------------------------------------------------- 1 | // 2 | // No types are written throughout this entire program. 3 | // 4 | 5 | use core {*} 6 | 7 | main :: () { 8 | object := .{ 9 | x = 0.0, y = 0.0, 10 | vx = 10.0, vy = 10.0, 11 | ax = -20.0, ay = -100.0 12 | }; 13 | 14 | for 40 { 15 | step_physics(&object, 0.01); 16 | printf("{}\n", object); 17 | } 18 | } 19 | 20 | step_physics :: (obj, dt) => { 21 | obj.x += 0.5 * obj.ax * dt * dt + obj.vx * dt; 22 | obj.y += 0.5 * obj.ay * dt * dt + obj.vy * dt; 23 | obj.vx += obj.ax * dt; 24 | obj.vy += obj.ay * dt; 25 | 26 | if obj.y < 0 { 27 | obj.y = 0; 28 | obj.vy = 0; 29 | obj.vx *= 0.05; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/operator_overload: -------------------------------------------------------------------------------- 1 | (2.0000, 4.0000) 2 | (2.0000, 2.0000) 3 | (-3.0000, 2.0000) 4 | (13.0000, 24.0000) 5 | 2.0000 3.0000 5.0000 7.0000 13.0000 24.0000 6 | (-5.0000, 6.0000) 7 | World! 8 | -------------------------------------------------------------------------------- /tests/operators_as_methods: -------------------------------------------------------------------------------- 1 | If works! 2 | Working! 3 | -------------------------------------------------------------------------------- /tests/operators_as_methods.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | use runtime 3 | 4 | #inject runtime.vars.Onyx_Enable_Operator_Methods :: true 5 | 6 | main :: () { 7 | Point :: struct { 8 | x, y: i32; 9 | 10 | __eq :: (p1, p2: Point) => { 11 | return p1.x == p2.x && p1.y == p2.y; 12 | } 13 | } 14 | 15 | p := Point.{1, 2}; 16 | 17 | if p == Point.{1, 2} { 18 | println("If works!"); 19 | } 20 | 21 | switch p { 22 | case .{0, 0} --- 23 | case .{1, 2} do println("Working!"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/osad_test: -------------------------------------------------------------------------------- 1 | Foo { 2 | nums = [ 3 | 2, 4 | 3, 5 | 5, 6 | 7, 7 | 11 8 | ], 9 | bar = Bar { 10 | name = "Joe", 11 | foos = [ 12 | Foo { 13 | nums = [ 14 | 1, 15 | 2, 16 | 3 17 | ], 18 | bar = Bar { 19 | name = "", 20 | foos = [ 21 | ] 22 | } 23 | }, 24 | Foo { 25 | nums = [ 26 | 4, 27 | 5, 28 | 6 29 | ], 30 | bar = Bar { 31 | name = "", 32 | foos = [ 33 | ] 34 | } 35 | } 36 | ] 37 | } 38 | } 39 | Foo { 40 | nums = [ 41 | 2, 42 | 3, 43 | 5, 44 | 7, 45 | 11 46 | ], 47 | bar = Bar { 48 | name = "Joe", 49 | foos = [ 50 | Foo { 51 | nums = [ 52 | 1, 53 | 2, 54 | 3 55 | ], 56 | bar = Bar { 57 | name = "", 58 | foos = [ 59 | ] 60 | } 61 | }, 62 | Foo { 63 | nums = [ 64 | 4, 65 | 5, 66 | 6 67 | ], 68 | bar = Bar { 69 | name = "", 70 | foos = [ 71 | ] 72 | } 73 | } 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/osad_test.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core.encoding.osad 3 | 4 | use core {printf} 5 | 6 | Foo :: struct { 7 | nums: [] i32; 8 | bar: Bar; 9 | } 10 | 11 | Bar :: struct { 12 | name: str; 13 | foos: [] Foo; 14 | } 15 | 16 | main :: () { 17 | f := Foo.{ 18 | nums = .[2, 3, 5, 7, 11], 19 | bar = .{ 20 | name = "Joe", 21 | foos = .[ 22 | .{ .[ 1, 2, 3 ], .{} }, 23 | .{ .[ 4, 5, 6 ], .{} }, 24 | ] 25 | } 26 | }; 27 | 28 | s := osad.serialize(f)->unwrap(); 29 | 30 | new_f := osad.deserialize(Foo, s)->unwrap(); 31 | 32 | 33 | printf("{p}\n", f); 34 | printf("{p}\n", new_f); 35 | } 36 | -------------------------------------------------------------------------------- /tests/overload_precedence: -------------------------------------------------------------------------------- 1 | Option M 2 | Option X 3 | Option R 4 | Option Z 5 | -------------------------------------------------------------------------------- /tests/overload_precedence.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | overloaded :: #match { 6 | #order 10 (x: i32) { println("Option X"); }, 7 | #order 5 (y: i32) { println("Option Y"); }, 8 | #order 4 (z: i32) { println("Option Z"); }, 9 | } 10 | 11 | main :: (args: [] cstr) { 12 | overloaded(10); 13 | overloaded(x=10); 14 | overloaded(r=10); 15 | overloaded(z=10); 16 | } 17 | 18 | #match #order 3 overloaded (q: i32) { println("Option Q"); } 19 | #match #order 2 overloaded (r: i32) { println("Option R"); } 20 | #match #order 1 overloaded (m: i32) { println("Option M"); } 21 | -------------------------------------------------------------------------------- /tests/overload_return_type: -------------------------------------------------------------------------------- 1 | Working 2 | Also working 3 | Again, working 4 | Super working 5 | -------------------------------------------------------------------------------- /tests/overload_return_type.onyx: -------------------------------------------------------------------------------- 1 | 2 | use core 3 | use core { println } 4 | 5 | main :: () { 6 | overloaded_proc(i32.{}) |> println(); 7 | overloaded_proc(f32.{}) |> println(); 8 | overloaded_proc(main) |> println(); 9 | overloaded_proc() |> println(); 10 | } 11 | 12 | overloaded_proc :: #match -> str {} 13 | 14 | #overload 15 | overloaded_proc :: (_: i32) -> str { 16 | return "Working"; 17 | } 18 | 19 | #overload 20 | overloaded_proc :: (_: f32) => { 21 | return "Also working"; 22 | } 23 | 24 | #overload 25 | overloaded_proc :: (_) => { 26 | return "Again, working"; 27 | } 28 | 29 | #overload 30 | overloaded_proc :: macro () => "Super working"; 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/overload_with_autocast: -------------------------------------------------------------------------------- 1 | Called i32, i32 2 | Called f32, str 3 | -------------------------------------------------------------------------------- /tests/overload_with_autocast.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core 4 | use core {println} 5 | 6 | overloaded :: #match { 7 | (x: str, y: i32) do println("Called str, i32"); , 8 | (x: f32, y: str) do println("Called f32, str"); , 9 | (x: i32, y: i32) do println("Called i32, i32"); , 10 | } 11 | 12 | main :: (args: [] cstr) { 13 | x: i32 = 1234; 14 | overloaded(~~x, 4); 15 | 16 | y: i32 = 1234; 17 | overloaded(~~x, "Test"); 18 | } 19 | -------------------------------------------------------------------------------- /tests/parallel_for.onyx: -------------------------------------------------------------------------------- 1 | use core {sync, iter, println} 2 | 3 | main :: () { 4 | sum := 0; 5 | 6 | thread_data := .{ 7 | sum = &sum, 8 | mutex = sync.Mutex.{}, 9 | }; 10 | sync.mutex_init(&thread_data.mutex); 11 | 12 | iter.parallel_for(0 .. 10000, 4, &thread_data) { 13 | sync.scoped_mutex(&thread_data.mutex); 14 | *thread_data.sum += it; 15 | } 16 | 17 | println(sum); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /tests/persist_locals: -------------------------------------------------------------------------------- 1 | 200 2 | 3 | 1 2 3 4 5 6 7 8 9 55 4 | 10 5 | 11 12 13 14 15 16 17 18 19 20 6 | 21 22 23 24 25 26 27 28 29 30 7 | 31 32 33 34 35 36 37 38 39 40 8 | 41 42 43 44 45 46 47 48 49 50 9 | 51 52 53 54 55 56 57 58 59 60 10 | 61 62 63 64 65 66 67 68 69 70 11 | 71 72 73 74 75 76 77 78 79 23416728348467685 12 | -------------------------------------------------------------------------------- /tests/persist_locals.onyx: -------------------------------------------------------------------------------- 1 | // This test does not make a whole ton of sense, but it does thoroughly test the #persist local capability. 2 | 3 | #load "core/module" 4 | 5 | use core {*} 6 | 7 | 8 | main :: (args: [] cstr) { 9 | 10 | foo(10); 11 | foo(30); 12 | foo(60); 13 | result := foo(100); 14 | println(result); 15 | 16 | cached_fib(10) |> println(); 17 | cached_fib(80) |> println(); 18 | 19 | } 20 | 21 | foo :: (x: i32) -> i32 { 22 | #persist total := 0; 23 | 24 | total += x; 25 | return total; 26 | } 27 | 28 | 29 | cached_fib :: (n: u64) -> u64 { 30 | #persist cache : map.Map(u64, u64); 31 | _ :: #init () { map.init(&cache); }; 32 | 33 | if n <= 1 do return n; 34 | 35 | map.get(&cache, n)->with([n] { return n; }); 36 | 37 | res := cached_fib(n - 1) + cached_fib(n - 2); 38 | map.put(&cache, n, res); 39 | 40 | print_cache_size(); 41 | 42 | return res; 43 | 44 | // This can see cache because it is statically lexically scoped. 45 | print_cache_size :: () { 46 | #persist a := 0; 47 | if a % 10 == 0 { 48 | print("\n"); 49 | a = 0; 50 | } 51 | a += 1; 52 | 53 | printf("{} ", cache.entries.count); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/poly_struct_in_type_info: -------------------------------------------------------------------------------- 1 | Base 2 | Base([] u8) { const = 10, dynamic = "Hello" } 3 | true 4 | false 5 | -------------------------------------------------------------------------------- /tests/poly_struct_in_type_info.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | use runtime.info 5 | 6 | Base :: struct (T: type_expr) { 7 | const: i32; 8 | dynamic: T; 9 | } 10 | 11 | main :: (args) => { 12 | printf("{}\n", Base); 13 | 14 | x := Base(str).{ 10, "Hello" }; 15 | printf("{}\n", x); 16 | printf("{}\n", info.struct_constructed_from(typeof x, Base)); 17 | 18 | y: Allocator; 19 | printf("{}\n", info.struct_constructed_from(typeof y, Base)); 20 | } -------------------------------------------------------------------------------- /tests/poly_structs_with_values: -------------------------------------------------------------------------------- 1 | 12345 2 | 12345 3 | 12345 4 | 12345 5 | 1234 6 | Hello World! 7 | Hello World! 8 | -------------------------------------------------------------------------------- /tests/poly_structs_with_values.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | NewPolyStruct :: struct (T: type_expr, N: i32) { 7 | x : [N] T; 8 | y : [N] f32; 9 | } 10 | 11 | nps : NewPolyStruct(i32, 4); 12 | 13 | for &x in nps.x do *x = 12345; 14 | for &y in nps.y do *y = 67890; 15 | 16 | for x in nps.x do println(x); 17 | 18 | 19 | 20 | 21 | 22 | SimpleWithDefault :: struct (T: type_expr, default: str) { 23 | x : T; 24 | str_member : str = default; 25 | } 26 | 27 | swd := SimpleWithDefault(i32, "Hello World!").{ x = 1234 }; 28 | println(swd.x); 29 | println(swd.str_member); 30 | poly_match(swd); 31 | 32 | poly_match :: (swd: SimpleWithDefault($T, $D)) do println(D); 33 | } 34 | -------------------------------------------------------------------------------- /tests/polymorphic_array_lengths: -------------------------------------------------------------------------------- 1 | 1 2 3 4 5 0.0000 2 | 1.0000 3 | 1.4142 4 | 1.7320 5 | 2.0000 6 | 2.2360 7 | 2.4494 8 | 2.6457 9 | 2.8284 10 | 3.0000 11 | 3.1622 12 | 3.3166 13 | 3.4641 14 | 3.6055 15 | 3.7416 16 | 3.8729 17 | 4.0000 18 | 4.1231 19 | 4.2426 20 | 4.3588 21 | -------------------------------------------------------------------------------- /tests/polymorphic_array_lengths.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | arr := u32.[ 1, 2, 3, 4, 5 ]; 7 | for elem in array_to_slice(arr) do printf("{} ", elem); 8 | 9 | roots : [20] f32; 10 | compute_roots(roots); 11 | 12 | for root in roots do println(root); 13 | 14 | array_to_slice :: (arr: [$N] $T) -> [] T { 15 | return (#type [] T).{ ~~arr, N }; 16 | } 17 | 18 | compute_roots :: (arr: [$N] f32) { 19 | for i in 0 .. N { 20 | arr[i] = math.sqrt(cast(f32) i); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/remove_test: -------------------------------------------------------------------------------- 1 | [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 ] 2 | [ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 ] 3 | -------------------------------------------------------------------------------- /tests/remove_test.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args) => { 6 | x: [..] i32; 7 | for 25 do x << it; 8 | 9 | println(x); 10 | 11 | for iter.as_iter(&x) { 12 | if it % 2 == 0 { 13 | #remove; 14 | } 15 | } 16 | 17 | println(x); 18 | } 19 | -------------------------------------------------------------------------------- /tests/sets: -------------------------------------------------------------------------------- 1 | 5 2 | 6 3 | true 4 | -------------- 5 | 6 6 | false 7 | -------------------------------------------------------------------------------- /tests/sets.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | main :: (args: [] cstr) { 6 | 7 | S := set.make(i32); 8 | 9 | set.insert(&S, 5); 10 | set.insert(&S, 5); 11 | set.insert(&S, 6); 12 | for entry in S.entries do println(entry.value); 13 | 14 | println(set.has(&S, 5)); 15 | 16 | println("--------------"); 17 | set.remove(&S, 5); 18 | for entry in S.entries do println(entry.value); 19 | println(set.has(&S, 5)); 20 | } -------------------------------------------------------------------------------- /tests/stdlib/base64: -------------------------------------------------------------------------------- 1 | Many hands make light work. 2 | light w 3 | light wo 4 | light wor 5 | 6 | 7 | TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu 8 | bGlnaHQgdw== 9 | bGlnaHQgd28= 10 | bGlnaHQgd29y 11 | bGlnaHQgd29yaw== 12 | -------------------------------------------------------------------------------- /tests/stdlib/base64.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core.encoding.base64 3 | 4 | decode_test :: () { 5 | for .[ 6 | "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu", 7 | "bGlnaHQgdw==", 8 | "bGlnaHQgd28=", 9 | "bGlnaHQgd29y", 10 | ] { 11 | core.println(base64.decode(it)); 12 | } 13 | } 14 | 15 | encode_test :: () { 16 | for .[ 17 | "Many hands make light work.", 18 | "light w", 19 | "light wo", 20 | "light wor", 21 | "light work", 22 | ] { 23 | encoded := base64.encode(it); 24 | core.println(encoded); 25 | } 26 | } 27 | 28 | main :: () { 29 | decode_test(); 30 | core.println("\n"); 31 | encode_test(); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /tests/stdlib/conv_parse: -------------------------------------------------------------------------------- 1 | Some(1203) 2 | Some(45.3199) 3 | Some(72) 4 | Some(Coconut) 5 | [ Some(12), Some(34), Some(56), Some(78), Some(90) ] 6 | -------------------------------------------------------------------------------- /tests/stdlib/conv_parse.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | main :: () { 4 | conv.parse(i32, "1203") |> println(); 5 | conv.parse(f32, "45.32") |> println(); 6 | conv.parse(? i8, "72") |> Optional.flatten() |> println(); 7 | 8 | conv.parse(Food, "2") |> println(); 9 | 10 | "12 34 56 78 90" 11 | |> string.split_iter(" ") 12 | |> iter.map(x => conv.parse(i32, x)) 13 | |> iter.collect() 14 | |> println(); 15 | } 16 | 17 | Food :: enum { 18 | Apple; 19 | Banana; 20 | Coconut; 21 | } 22 | -------------------------------------------------------------------------------- /tests/stdlib/os_path: -------------------------------------------------------------------------------- 1 | true: .==. 2 | true: abc==abc 3 | true: ..==.. 4 | true: ../../abc==../../abc 5 | true: /==/ 6 | true: abc==abc 7 | true: a/b/c==a/b/c 8 | true: /abc==/abc 9 | true: abc/def/ghi==abc/def/ghi 10 | true: /abc==/abc 11 | true: /abc==/abc 12 | true: abc/def==abc/def 13 | true: /abc/def==/abc/def 14 | true: abc==abc 15 | true: abc/def/jkl==abc/def/jkl 16 | true: abc/jkl==abc/jkl 17 | true: def==def 18 | true: def==def 19 | true: ../../def==../../def 20 | true: abc==abc 21 | -------------------------------------------------------------------------------- /tests/stdlib/os_path.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | main :: () { 4 | for t in Pair(str, str).[ 5 | .{"", "."}, 6 | .{"abc", "abc"}, 7 | .{"..", ".."}, 8 | .{"../../abc", "../../abc"}, 9 | .{"/", "/"}, 10 | 11 | .{"abc/", "abc"}, 12 | .{"a/b/c/", "a/b/c"}, 13 | .{"/abc/", "/abc"}, 14 | 15 | .{"abc//def//ghi", "abc/def/ghi"}, 16 | .{"//abc", "/abc"}, 17 | .{"//abc//", "/abc"}, 18 | 19 | .{"abc/./def", "abc/def"}, 20 | .{"/./abc/def", "/abc/def"}, 21 | .{"abc/.", "abc"}, 22 | 23 | .{"abc/def/ghi/../jkl", "abc/def/jkl"}, 24 | .{"abc/def/../ghi/../jkl", "abc/jkl"}, 25 | 26 | .{"abc/./../def", "def"}, 27 | .{"abc//./../def", "def"}, 28 | .{"abc/../../././../def", "../../def"}, 29 | 30 | .{"abc/def/..", "abc"} 31 | ] { 32 | cleaned := os.path_clean(t.first); 33 | printf("{}: {}=={}\n", cleaned == t.second, cleaned, t.second); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/string_stream_test: -------------------------------------------------------------------------------- 1 | This 2 | is 3 | a test string that can be read. 4 | 1234 5 | 4567 6 | 5801 7 | -------------------------------------------------------------------------------- /tests/string_stream_test.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core 4 | use core.io 5 | use core {println} 6 | 7 | main :: (args: [] cstr) { 8 | some_string := "This is a test string that can be read.\n\n\n\n\n\n1234 4567"; 9 | 10 | sstream := io.buffer_stream_make(some_string); 11 | sreader := io.reader_make(&sstream); 12 | 13 | for i in 0 .. 2 { 14 | word := io.read_word(&sreader, allocator=context.temp_allocator); 15 | println(word); 16 | } 17 | 18 | println(io.read_line(&sreader, consume_newline=false, allocator=context.temp_allocator)); 19 | 20 | a := io.read_u32(&sreader); 21 | b := io.read_u32(&sreader); 22 | 23 | println(a); 24 | println(b); 25 | println(a + b); 26 | } 27 | -------------------------------------------------------------------------------- /tests/struct_robustness: -------------------------------------------------------------------------------- 1 | Testing a simple structure. 2 | SimpleStruct<16, 4>(41, 67, Steve) 3 | 4 | 5 | Testing a simple union. 6 | 0x3F000000 == 0x3F000000 7 | 8 | 9 | Testing a struct with default values. 10 | DefaultedStruct(0, 1.0000, 2, 3.0000) 11 | DefaultedStruct(3, 1.0000, 2, 0.0000) 12 | 13 | 14 | Testing a struct with `use`. 15 | StructWithUse(1234, (1.0000, 2.0000), 5678) 16 | StructWithUse(1234, (1.0000, 2.0000), 5678) 17 | 18 | 19 | Testing a polymorphic struct. 20 | PolyStruct(1234, 5678.0000) 21 | PolyStruct(1234.0000, 5678) 22 | 23 | 24 | Testing a polymorphic struct with default values. 25 | PolyStruct(1234, 5678.0000) 26 | 27 | 28 | Testing a union with use. 29 | Union(10, 20) 30 | Union(Joe) 31 | 32 | 33 | Testing a polymorphic union. 34 | PolyUnion(Hello World.) 35 | PolyUnion(1234) 36 | 37 | 38 | Testing a polymorphic union with use. 39 | 8 == 16 40 | 0, 5678.0000 41 | -------------------------------------------------------------------------------- /tests/struct_use_pointer_member: -------------------------------------------------------------------------------- 1 | Hello, I am Billy! 2 | Go away!! (&Person) -> void 3 | -------------------------------------------------------------------------------- /tests/struct_use_pointer_member.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | use core {*} 3 | 4 | Person_Vtable :: struct { 5 | greet: (&Person) -> void; 6 | } 7 | 8 | Person :: struct { 9 | use vtable: &Person_Vtable; 10 | 11 | name: str; 12 | } 13 | 14 | nice_person := Person_Vtable.{ 15 | greet = (use p: &Person) { 16 | printf("Hello, I am {}!\n", name); 17 | } 18 | } 19 | 20 | mean_person := Person_Vtable.{ 21 | greet = (use p: &Person) { 22 | printf("Go away!! {}\n", typeof greet); 23 | } 24 | } 25 | 26 | main :: (args) => { 27 | billy := Person.{ &nice_person, "Billy" }; 28 | charles := Person.{ &mean_person, "Charles" }; 29 | 30 | billy->greet(); 31 | charles->greet(); 32 | } 33 | -------------------------------------------------------------------------------- /tests/structure_method_tag: -------------------------------------------------------------------------------- 1 | Some tag 2 | Called the method! 3 | -------------------------------------------------------------------------------- /tests/structure_method_tag.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | use runtime 3 | 4 | Some_Structure :: struct { 5 | @"Some tag" 6 | some_method :: () { 7 | println("Called the method!"); 8 | } 9 | } 10 | 11 | main :: () { 12 | the_type := Some_Structure; 13 | the_method := *cast(&()->void, the_type->info()->as_struct().methods[0].func.data); 14 | the_tag := misc.any_as(runtime.info.get_tags_for_procedure(the_method)[0], str); 15 | println(*the_tag); 16 | 17 | the_method(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/switch_expressions: -------------------------------------------------------------------------------- 1 | Val3 2 | Val1 3 | 123 4 | 12.3400 5 | A string 6 | -------------------------------------------------------------------------------- /tests/switch_expressions.onyx: -------------------------------------------------------------------------------- 1 | use core {*} 2 | 3 | Foo :: enum { 4 | Val1; 5 | Val2; 6 | Val3; 7 | } 8 | 9 | assignment_test :: () { 10 | v: Foo = switch 3 { 11 | case 1 => .Val1; 12 | case 2 => .Val2; 13 | case 3 => .Val3; 14 | }; 15 | 16 | printf("{}\n", v); 17 | } 18 | 19 | quick_map_test :: () { 20 | println(quick_map(3)); 21 | 22 | quick_map :: (n: i32) -> Foo { 23 | return switch n { 24 | case 4 => .Val1; 25 | case 5 => .Val2; 26 | case 6 => .Val3; 27 | case #default => .Val1; 28 | }; 29 | } 30 | } 31 | 32 | quick_union_map :: () { 33 | 34 | quick_map(SomeUnion.{ x = 123 }) |> println(); 35 | quick_map(SomeUnion.{ y = 12.34 }) |> println(); 36 | quick_map(SomeUnion.{ z = "A string" }) |> println(); 37 | 38 | SomeUnion :: union { 39 | x: i32; 40 | y: f32; 41 | z: str; 42 | } 43 | 44 | quick_map :: (v: $T) => switch v { 45 | case .z as val => val; 46 | case .y as val => conv.format("{}", val); 47 | case .x as val => conv.format("{}", val); 48 | } 49 | } 50 | 51 | main :: () { 52 | assignment_test(); 53 | quick_map_test(); 54 | quick_union_map(); 55 | } -------------------------------------------------------------------------------- /tests/switch_using_equals: -------------------------------------------------------------------------------- 1 | Got some! 2 | Got thing! 3 | Got default! 4 | 1, 0 5 | -------------------------------------------------------------------------------- /tests/switch_using_equals.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*} 4 | 5 | Vector2 :: struct { x, y: i32; } 6 | #operator == macro (v1: Vector2, v2: Vector2) => v1.x == v2.x && v1.y == v2.y; 7 | 8 | none_of_the_above :: [] { 9 | case #default { 10 | println("Got default!"); 11 | } 12 | } 13 | 14 | main :: (args: [] cstr) { 15 | for .[ "Some", "Thing", "Other" ] { 16 | switch it { 17 | case "Thing" do println("Got thing!"); 18 | case "Some" do println("Got some!"); 19 | #unquote none_of_the_above; 20 | } 21 | } 22 | 23 | v := Vector2.{ 1, 0 }; 24 | switch v { 25 | case .{ 0, 0 } do println("0, 0"); 26 | case .{ 0, 1 } do println("0, 1"); 27 | case .{ 1, 0 } do println("1, 0"); 28 | case .{ 1, 1 } do println("1, 1"); 29 | 30 | #unquote none_of_the_above; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/tagged_globals: -------------------------------------------------------------------------------- 1 | i32 2 | package_id[7] 3 | 1 4 | Default value is: 1234 5 | New value is: 5678 6 | Test that strings work! 7 | ============================================== 8 | Something_Interesting { version = 10, about = "This is a cool variable" } 9 | Something_Interesting { version = 20, about = "This is another cool variable!" } 10 | -------------------------------------------------------------------------------- /tests/tagged_globals.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | use core {*} 4 | use runtime.info 5 | 6 | @"Test that strings work!" 7 | x: i32 = 1234; 8 | 9 | 10 | Something_Interesting :: struct { 11 | version: u32; 12 | about: str; 13 | } 14 | 15 | @Something_Interesting.{ 10, "This is a cool variable" } 16 | value_1 := "Working!" 17 | 18 | @Something_Interesting.{ 20, "This is another cool variable!" } 19 | value_2 := "Also working!" 20 | 21 | 22 | main :: () { 23 | for info.tagged_globals { 24 | if it.type != i32 do continue; 25 | println(it.type); 26 | println(it.pack); 27 | println(it.tags.count); 28 | 29 | val_ptr: &i32 = it.data; 30 | printf("Default value is: {*}\n", val_ptr); 31 | 32 | *val_ptr = 5678; 33 | printf("New value is: {*}\n", val_ptr); 34 | 35 | for t in it.tags { 36 | if t.type == str { 37 | printf("{*}\n", misc.any_as(t, str)); 38 | } 39 | } 40 | } 41 | 42 | println("=============================================="); 43 | 44 | for info.get_globals_with_tag(Something_Interesting) { 45 | println(*it.tag); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /tests/tagged_unions: -------------------------------------------------------------------------------- 1 | int(123) 2 | float(100.0000) 3 | string("Working") 4 | This is a string: This works 5 | This is an integer: 9876 6 | 123 7 | 456 8 | Error(Process_Error("bad data")) 9 | A wrapped value 10 | 2 11 | Bool(true) 12 | -------------------------------------------------------------------------------- /tests/utf8_test: -------------------------------------------------------------------------------- 1 | 🂦 🂧 🂨 🂩 🂪 🂫 🂬 🂭 🂮 🂯 🂰 🂱 🂲 🂳 🂴 🂵 🂶 🂷 🂸 🂹 🂺 🂻 🂼 🂽 🂾 🂿 🃀 🃁 🃂 🃃 🃄 🃅 🃆 🃇 🃈 🃉 🃊 🃋 🃌 🃍 🃎 🃏 🃐 🃑 🃒 🃓 🃔 🃕 🃖 🃗 🃘 🃙 🃚 🃛 🃜 🃝 🃞 🃟 2 | 🂣🂤🂥🂦🂧🂨🂩 3 | 🂦 4 | -------------------------------------------------------------------------------- /tests/utf8_test.onyx: -------------------------------------------------------------------------------- 1 | use core 2 | use core.encoding.utf8 3 | use runtime 4 | 5 | use core {print, println, printf} 6 | 7 | #inject runtime.vars.Enable_Heap_Debug :: true 8 | 9 | main :: () { 10 | output := make(dyn_str); 11 | defer delete(&output); 12 | 13 | for i in 0x1F0A0 .. 0x1F0E0 { 14 | utf8.append_rune(&output, i); 15 | } 16 | 17 | tmp: str = output; 18 | utf8.advance_rune(&tmp, 6); 19 | 20 | for utf8.runes(tmp) { 21 | printf("{} ", it.bytes); 22 | } 23 | print("\n"); 24 | 25 | println(utf8.slice(output, 3, 10)); 26 | 27 | println(utf8.next_rune(tmp)); 28 | } 29 | -------------------------------------------------------------------------------- /tests/vararg_test: -------------------------------------------------------------------------------- 1 | foo 2 | 1 3 | 2 4 | 1077936128 5 | 1084227584 6 | bar 7 | 1 8 | Hello, 1234, World! 9 | -------------------------------------------------------------------------------- /tests/vararg_test.onyx: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | #load "core/module" 4 | 5 | use core {*}; 6 | 7 | old_va_test :: (prefix: str, va: ..i32) { 8 | println(prefix); 9 | for v in va do println(v); 10 | } 11 | 12 | new_va_test :: (prefix: str, va: ..any) { 13 | println(prefix); 14 | 15 | for i in 0 .. va.count { 16 | // The right way to do it is this: 17 | // x := * misc.any_as(va[i], i32); 18 | 19 | x := *cast(&i32, va[i].data); 20 | println(x); 21 | } 22 | } 23 | 24 | main :: (args: [] cstr) { 25 | new_va_test("foo", 1, 2, 3.0f, 5.0f); 26 | old_va_test("bar", 1); 27 | 28 | printf("Hello, {}, {}!\n", 1234, "World"); 29 | } 30 | -------------------------------------------------------------------------------- /tests/where_clauses: -------------------------------------------------------------------------------- 1 | [ 2.0000, 4.0000, 6.0000, 8.0000 ] 2 | -------------------------------------------------------------------------------- /tests/where_clauses.onyx: -------------------------------------------------------------------------------- 1 | #load "core/module" 2 | 3 | use core {*}; 4 | 5 | main :: () { 6 | a := f32.[ 1, 2, 3, 4 ]; 7 | b := f32.[ 1, 2, 3, 4 ]; 8 | c := add(a, b); 9 | println(c); 10 | 11 | d: Foo(typeof c); 12 | d.values = c; 13 | } 14 | 15 | Adder :: interface(T: type_expr) { 16 | t as T; 17 | 18 | { t + t } -> T; 19 | } 20 | 21 | add :: (a, b: [$N]$T) -> [N] T where Adder(T), N > 0, N <= 4 22 | { 23 | return a + b; 24 | } 25 | 26 | CanBeIndexed :: interface(T: type_expr) { 27 | t as T; 28 | 29 | t[0]; 30 | } 31 | 32 | Foo :: struct (T: type_expr) where CanBeIndexed(T) { 33 | values: T; 34 | } 35 | 36 | 37 | --------------------------------------------------------------------------------