├── book ├── .gitignore ├── src │ ├── string_literals.md │ ├── deprecated.md │ ├── advanced.md │ ├── concepts.md │ ├── try_operator.md │ ├── streams.md │ ├── dynamic_types.md │ ├── structs.md │ └── hot_reloading.md ├── book.toml └── README.md ├── crates ├── rune │ ├── .gitignore │ ├── Rune.toml │ ├── src │ │ ├── tests │ │ │ ├── workspace │ │ │ │ ├── package-a │ │ │ │ │ ├── Rune.toml │ │ │ │ │ ├── src │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ └── bin │ │ │ │ │ │ │ ├── named-executable.rn │ │ │ │ │ │ │ └── multi-file-executable │ │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ │ └── module │ │ │ │ │ │ │ └── mod.rn │ │ │ │ │ ├── tests │ │ │ │ │ │ ├── fire │ │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ │ └── main.rn │ │ │ │ │ │ └── smoke.rn │ │ │ │ │ ├── examples │ │ │ │ │ │ ├── simple.rn │ │ │ │ │ │ └── multi-file-example │ │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ │ └── main.rn │ │ │ │ │ └── benches │ │ │ │ │ │ ├── multi-file-bench │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ └── collatz.rn │ │ │ │ │ │ └── collatz.rn │ │ │ │ ├── nested │ │ │ │ │ └── package-b │ │ │ │ │ │ ├── Rune.toml │ │ │ │ │ │ ├── src │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ └── bin │ │ │ │ │ │ │ ├── named-executable.rn │ │ │ │ │ │ │ └── multi-file-executable │ │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ │ └── module │ │ │ │ │ │ │ └── mod.rn │ │ │ │ │ │ ├── tests │ │ │ │ │ │ ├── fire │ │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ │ └── main.rn │ │ │ │ │ │ └── smoke.rn │ │ │ │ │ │ ├── examples │ │ │ │ │ │ ├── simple.rn │ │ │ │ │ │ └── multi-file-example │ │ │ │ │ │ │ ├── lib.rn │ │ │ │ │ │ │ └── main.rn │ │ │ │ │ │ └── benches │ │ │ │ │ │ ├── multi-file-bench │ │ │ │ │ │ ├── main.rn │ │ │ │ │ │ └── collatz.rn │ │ │ │ │ │ └── collatz.rn │ │ │ │ └── Rune.toml │ │ │ ├── vm_blocks.rs │ │ │ ├── vm_not_used.rs │ │ │ ├── bug_428.rs │ │ │ ├── vm_assign_exprs.rs │ │ │ ├── vm_async_block.rs │ │ │ ├── compiler_fn.rs │ │ │ ├── esoteric_impls.rs │ │ │ ├── compiler_expr_assign.rs │ │ │ ├── vm_test_mod.rs │ │ │ ├── bug_454.rs │ │ │ ├── vm_result.rs │ │ │ ├── compiler_warnings.rs │ │ │ ├── continue_.rs │ │ │ ├── unreachable.rs │ │ │ ├── bug_422.rs │ │ │ ├── result.rs │ │ │ ├── rename_type.rs │ │ │ ├── bug_417.rs │ │ │ ├── capture.rs │ │ │ ├── static_typing.rs │ │ │ ├── comments.rs │ │ │ ├── binary.rs │ │ │ ├── compiler_patterns.rs │ │ │ ├── wildcard_imports.rs │ │ │ ├── vm_try.rs │ │ │ ├── vm_test_instance_fns.rs │ │ │ ├── f64.rs │ │ │ ├── compiler_literals.rs │ │ │ ├── moved.rs │ │ │ ├── compiler_use.rs │ │ │ ├── macros │ │ │ │ └── stringy_math.rs │ │ │ └── option.rs │ │ ├── hashbrown │ │ │ └── mod.rs │ │ ├── runtime │ │ │ ├── slice.rs │ │ │ ├── env │ │ │ │ └── std.rs │ │ │ ├── budget │ │ │ │ ├── std.rs │ │ │ │ └── no_std.rs │ │ │ ├── steps_between.rs │ │ │ ├── protocol.rs │ │ │ ├── iterator.rs │ │ │ └── select.rs │ │ ├── doc │ │ │ ├── static │ │ │ │ ├── fonts │ │ │ │ │ ├── FiraSans-Medium.woff2 │ │ │ │ │ ├── FiraSans-Regular.woff2 │ │ │ │ │ ├── SourceSerif4-Bold.woff2 │ │ │ │ │ ├── SourceCodePro-It.ttf.woff2 │ │ │ │ │ ├── SourceCodePro-Regular.woff2 │ │ │ │ │ ├── SourceSerif4-Regular.woff2 │ │ │ │ │ ├── SourceCodePro-Semibold.woff2 │ │ │ │ │ └── NanumBarunGothic-Regular.woff2 │ │ │ │ ├── macro.html.hbs │ │ │ │ ├── index.html.hbs │ │ │ │ ├── function.html.hbs │ │ │ │ └── layout.html.hbs │ │ │ ├── build │ │ │ │ └── js.rs │ │ │ └── mod.rs │ │ ├── hir │ │ │ ├── interpreter.rs │ │ │ ├── mod.rs │ │ │ └── arena │ │ │ │ └── tests.rs │ │ ├── item.rs │ │ ├── parse │ │ │ ├── traits.rs │ │ │ ├── resolve.rs │ │ │ ├── peek.rs │ │ │ └── id.rs │ │ ├── modules │ │ │ ├── macros.rs │ │ │ ├── hash.rs │ │ │ ├── i64.rs │ │ │ ├── u64.rs │ │ │ ├── num.rs │ │ │ ├── stream.rs │ │ │ ├── collections │ │ │ │ └── mod.rs │ │ │ └── slice.rs │ │ ├── languageserver │ │ │ ├── fs.rs │ │ │ └── tests.rs │ │ ├── cli │ │ │ └── languageserver.rs │ │ ├── ast │ │ │ ├── to_ast.rs │ │ │ ├── expr_vec.rs │ │ │ ├── utils.rs │ │ │ ├── expr_try.rs │ │ │ ├── prelude.rs │ │ │ ├── fn_arg.rs │ │ │ ├── expr_empty.rs │ │ │ ├── expr_assign.rs │ │ │ ├── tests.rs │ │ │ ├── expr_lit.rs │ │ │ ├── expr_group.rs │ │ │ ├── expr_await.rs │ │ │ ├── expr_continue.rs │ │ │ ├── expr_return.rs │ │ │ ├── expr_index.rs │ │ │ ├── expr_yield.rs │ │ │ ├── condition.rs │ │ │ ├── expr_call.rs │ │ │ ├── expr_break.rs │ │ │ ├── expr_loop.rs │ │ │ ├── expr_while.rs │ │ │ └── rn_type.rs │ │ ├── compile │ │ │ ├── v1 │ │ │ │ ├── mod.rs │ │ │ │ └── display_named.rs │ │ │ └── names │ │ │ │ └── tests.rs │ │ ├── module │ │ │ └── install_with.rs │ │ ├── ace │ │ │ ├── static │ │ │ │ └── rune-completer.js │ │ │ └── mod.rs │ │ ├── location.rs │ │ ├── workspace │ │ │ ├── glob │ │ │ │ └── tests.rs │ │ │ └── mod.rs │ │ ├── shared │ │ │ ├── gen.rs │ │ │ └── assert_send.rs │ │ ├── musli.rs │ │ └── serde.rs │ ├── tests │ │ ├── ui.rs │ │ ├── tuples.rn │ │ ├── ui │ │ │ ├── install_with_compat.rs │ │ │ └── install_with_compat.stderr │ │ ├── imports.rn │ │ ├── modules_inline.rn │ │ ├── char.rn │ │ ├── function_pointers.rn │ │ ├── modules_vis.rn │ │ ├── int_ops.rn │ │ ├── const.rn │ │ ├── reordering.rn │ │ ├── lazy_and_or.rn │ │ ├── float.rn │ │ ├── instance.rn │ │ ├── types.rn │ │ ├── non_ascii_idents.rn │ │ ├── option.rn │ │ ├── variants.rn │ │ ├── bug_838.rn │ │ ├── result.rn │ │ ├── try.rn │ │ ├── esoteric_impls.rn │ │ ├── typed_tuple.rn │ │ ├── blocks.rn │ │ ├── basics.rn │ │ └── select.rn │ └── benches │ │ ├── fib.rn │ │ └── primes.rn ├── rune-alloc │ ├── .gitignore │ ├── third-party │ │ └── .gitignore │ ├── src │ │ ├── serde │ │ │ └── mod.rs │ │ ├── option │ │ │ ├── mod.rs │ │ │ └── ext.rs │ │ ├── hint.rs │ │ ├── tests.rs │ │ ├── iter │ │ │ ├── mod.rs │ │ │ ├── join.rs │ │ │ └── try_cloned.rs │ │ ├── fmt │ │ │ └── impls.rs │ │ ├── btree │ │ │ ├── set_val.rs │ │ │ └── mod.rs │ │ ├── vec_deque │ │ │ └── macros.rs │ │ ├── limit │ │ │ ├── std.rs │ │ │ └── no_std.rs │ │ ├── testing │ │ │ └── rng.rs │ │ ├── callable.rs │ │ └── vec │ │ │ └── set_len_on_drop.rs │ └── tools │ │ └── import.ps1 ├── rune-wasm │ ├── .gitignore │ ├── rune.js │ ├── module.js │ ├── rollup.config.mjs │ ├── package.json │ └── src │ │ └── time.rs ├── rune-macros │ ├── tests │ │ └── derive.rs │ ├── src │ │ └── path_in.rs │ └── Cargo.toml ├── rune-core │ └── src │ │ ├── item.rs │ │ └── hash │ │ └── into_hash.rs ├── rune-modules │ └── src │ │ └── rand │ │ ├── error.rs │ │ └── os_error.rs ├── rune-cli │ ├── build.rs │ └── Cargo.toml ├── rune-languageserver │ ├── build.rs │ └── Cargo.toml ├── rune-alloc-macros │ └── Cargo.toml ├── rune-tracing-macros │ └── Cargo.toml └── rune-tracing │ └── Cargo.toml ├── site ├── .gitignore ├── content │ ├── play.md │ ├── posts │ │ ├── 2023-10-10-my-project-cli.png │ │ ├── 2023-10-10-is-alphabetic-doc.png │ │ └── _index.md │ └── rune.md ├── static │ └── img │ │ └── logo.png ├── templates │ ├── shortcodes │ │ ├── quote.html │ │ ├── vm.html │ │ └── yt.html │ ├── index.html │ ├── page.html │ └── post.html ├── sass │ ├── _shortcodes.scss │ └── _vars.scss ├── theme.toml └── config.toml ├── editors └── code │ ├── .yarnrc │ ├── .gitignore │ ├── assets │ ├── icon.png │ └── logo.png │ ├── .vscodeignore │ ├── LICENSE.md │ ├── src │ ├── test │ │ ├── suite │ │ │ ├── extension.test.ts │ │ │ └── index.ts │ │ └── runTest.ts │ ├── persistent_state.ts │ └── extension.ts │ ├── .vscode │ ├── settings.json │ ├── launch.json │ └── tasks.json │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── language-configuration.json │ └── LICENSE-MIT ├── scripts ├── book │ ├── the_stack │ │ ├── add.rn │ │ └── call_and_add.rn │ ├── getting_started │ │ ├── hello_world.rn │ │ └── dbg.rn │ ├── items_imports │ │ ├── bar.rn │ │ ├── foo │ │ │ └── mod.rn │ │ ├── missing_item.rn.fail │ │ ├── modules.rn │ │ ├── example_import.rn │ │ ├── inline_modules.rn │ │ └── item_keywords.rn │ ├── compiler_guide │ │ ├── closures.rn │ │ └── dead_code.rn │ ├── template_literals │ │ ├── not_a_template.rn │ │ └── basic_template.rn │ ├── functions │ │ ├── main_function.rn │ │ └── return_value.rn │ ├── tuples │ │ ├── basic_tuples.rn │ │ ├── tuple_masquerade.rn │ │ └── tuple_patterns.rn │ ├── types │ │ ├── bad_type_check.rn │ │ ├── type_check.rn │ │ ├── type_check_patterns.rn │ │ └── types.rn │ ├── primitives │ │ ├── copy.rn │ │ └── primitives.rn │ ├── control_flow │ │ ├── conditional.rn │ │ ├── conditional_else.rn │ │ ├── conditional_else_ifs.rn │ │ ├── numbers_game.rn │ │ └── first_match.rn │ ├── loops │ │ ├── loop_forever.rn │ │ ├── loop_break.rn │ │ └── while_loop.rn │ ├── vectors │ │ ├── vectors_rev.rn │ │ └── vectors.rn │ ├── variables │ │ ├── variables.rn │ │ ├── take_argument.rn │ │ ├── shared_ownership.rn │ │ └── is_readable.rn │ ├── instance_functions │ │ └── missing_instance_fn.rn │ ├── closures │ │ ├── basic_closure.rn │ │ ├── closure_move.rn.fail │ │ └── function_pointers.rn │ ├── pattern_matching │ │ ├── bind.rn │ │ ├── ignore.rn │ │ ├── rest_pattern.rn │ │ ├── fast_cars.rn │ │ └── big_match.rn │ ├── generators │ │ ├── states.rn │ │ ├── error.rn │ │ ├── fib_generator.rn │ │ ├── bootup.rn │ │ └── send_values.rn │ ├── async │ │ ├── async_blocks.rn │ │ ├── async_closure.rn │ │ ├── async_http.rn │ │ ├── async_http_timeout.rn │ │ └── async_http_concurrent.rn │ ├── dynamic_types │ │ └── greeting.rn │ ├── enums │ │ └── count_numbers.rn │ ├── try_operator │ │ └── basic_try.rn │ ├── objects │ │ ├── objects.rn │ │ └── json.rn │ ├── streams │ │ └── basic_stream.rn │ └── structs │ │ ├── user_database.rn │ │ └── struct_matching.rn ├── hello_world.rn ├── broken.rn ├── constant_expr.rn ├── json.rn ├── arrays.rn ├── reverse_iterator.rn ├── not_used.rn ├── signal.rn ├── fib.rn ├── numbers.rn ├── objects.rn ├── generator_as_iter.rn ├── compile-fail │ └── experimental_macro_error.rn.fail ├── strings.rn ├── primes.rn ├── rand.rn ├── http.rn ├── doc.rn ├── generator_resume.rn ├── async.rn └── controls.rn ├── no-std ├── .gitignore └── Cargo.toml ├── tools ├── builder │ ├── .gitignore │ ├── README.md │ └── Cargo.toml ├── site │ ├── .gitignore │ ├── README.md │ ├── Cargo.toml │ └── src │ │ └── main.rs └── generate │ ├── .gitignore │ ├── Cargo.toml │ └── README.md ├── examples ├── examples │ ├── test │ │ ├── module.rn │ │ └── main.rn │ ├── function_hash.rs │ └── lookup_function.rs ├── Rune.toml ├── ace │ ├── .gitignore │ └── README.md ├── README.md ├── scripts │ └── change_me.rn └── Cargo.toml ├── assets ├── icon.png ├── icon.xcf ├── logo.xcf └── social.png ├── benches ├── Rune.toml ├── Cargo.toml ├── README.md └── benches │ └── benchmarks │ └── external_functions.rs ├── .gitattributes ├── Rune.toml ├── .gitignore └── Cargo.toml /book/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /crates/rune/.gitignore: -------------------------------------------------------------------------------- 1 | /wip/ 2 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | public/* 2 | static/js -------------------------------------------------------------------------------- /crates/rune-alloc/.gitignore: -------------------------------------------------------------------------------- 1 | /patches/ 2 | -------------------------------------------------------------------------------- /editors/code/.yarnrc: -------------------------------------------------------------------------------- 1 | --ignore-engines true -------------------------------------------------------------------------------- /scripts/book/the_stack/add.rn: -------------------------------------------------------------------------------- 1 | 1 + 3 2 | -------------------------------------------------------------------------------- /crates/rune-alloc/third-party/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /no-std/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /crates/rune-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /out -------------------------------------------------------------------------------- /scripts/hello_world.rn: -------------------------------------------------------------------------------- 1 | println!("Hello World"); 2 | -------------------------------------------------------------------------------- /tools/builder/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /tools/site/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /tools/generate/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/serde/mod.rs: -------------------------------------------------------------------------------- 1 | mod de; 2 | mod ser; 3 | -------------------------------------------------------------------------------- /scripts/broken.rn: -------------------------------------------------------------------------------- 1 | let v = [1, 2, 3, 4]; 2 | 3 | dbg!(v); 4 | -------------------------------------------------------------------------------- /examples/examples/test/module.rn: -------------------------------------------------------------------------------- 1 | pub fn test() { 2 | 42 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/getting_started/hello_world.rn: -------------------------------------------------------------------------------- 1 | println!("Hello World"); 2 | -------------------------------------------------------------------------------- /scripts/book/items_imports/bar.rn: -------------------------------------------------------------------------------- 1 | pub fn number() { 2 | 1 3 | } 4 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/assets/icon.xcf -------------------------------------------------------------------------------- /assets/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/assets/logo.xcf -------------------------------------------------------------------------------- /crates/rune/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /examples/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /scripts/book/items_imports/foo/mod.rn: -------------------------------------------------------------------------------- 1 | pub fn number() { 2 | 2 3 | } 4 | -------------------------------------------------------------------------------- /site/content/play.md: -------------------------------------------------------------------------------- 1 | +++ 2 | template = "play.html" 3 | +++ 4 | 5 | The REP -------------------------------------------------------------------------------- /assets/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/assets/social.png -------------------------------------------------------------------------------- /benches/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-benches" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /scripts/constant_expr.rn: -------------------------------------------------------------------------------- 1 | const VALUE = 0b001 << 3; 2 | 3 | dbg!(VALUE == 8); 4 | -------------------------------------------------------------------------------- /scripts/json.rn: -------------------------------------------------------------------------------- 1 | let data = json::from_string("{\"key\": 42}"); 2 | dbg!(data); 3 | -------------------------------------------------------------------------------- /scripts/arrays.rn: -------------------------------------------------------------------------------- 1 | let a = [1, 2, 3, 4]; 2 | let b = [5, 6, 7, 8]; 3 | dbg!(a, b); 4 | -------------------------------------------------------------------------------- /scripts/book/compiler_guide/closures.rn: -------------------------------------------------------------------------------- 1 | let callable = || 42; 2 | dbg!(callable()); 3 | -------------------------------------------------------------------------------- /scripts/reverse_iterator.rn: -------------------------------------------------------------------------------- 1 | for v in (0..10).iter().rev() { 2 | dbg!(v); 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | **/generated.rs linguist-generated=true 2 | **/generated.rs -diff -merge 3 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/option/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::ext::OptionExt; 2 | pub(crate) mod ext; 3 | -------------------------------------------------------------------------------- /examples/ace/.gitignore: -------------------------------------------------------------------------------- 1 | rune-autocomplete.js 2 | rune-mode.js 3 | rune-highlight-rules.js 4 | -------------------------------------------------------------------------------- /scripts/book/template_literals/not_a_template.rn: -------------------------------------------------------------------------------- 1 | let vec = [1, 2, 3]; 2 | dbg!(`${vec}`); 3 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "a" 3 | version = "0.0.0" -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/src/lib.rn: -------------------------------------------------------------------------------- 1 | pub fn get_name() { 2 | "a/lib" 3 | } 4 | -------------------------------------------------------------------------------- /editors/code/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | server 4 | node_modules 5 | .vscode-test/ 6 | *.vsix 7 | -------------------------------------------------------------------------------- /scripts/book/functions/main_function.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("Hello World"); 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/tuples/basic_tuples.rn: -------------------------------------------------------------------------------- 1 | fn foo() { 2 | (1, "test") 3 | } 4 | 5 | dbg!(foo()); 6 | -------------------------------------------------------------------------------- /site/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/site/static/img/logo.png -------------------------------------------------------------------------------- /scripts/book/items_imports/missing_item.rn.fail: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let foo = Foo::new(); 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/template_literals/basic_template.rn: -------------------------------------------------------------------------------- 1 | let age = 30; 2 | dbg!(`I am ${age} years old!`); 3 | -------------------------------------------------------------------------------- /scripts/not_used.rn: -------------------------------------------------------------------------------- 1 | "hello world"; 2 | 'a'; 3 | [42, 42]; 4 | #{ "foo": 42, "bar": [1, 2, 3, 4] }; 5 | -------------------------------------------------------------------------------- /tools/site/README.md: -------------------------------------------------------------------------------- 1 | # site 2 | 3 | A small utility to build the guts of https://rune-rs.github.io 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "b" 3 | version = "0.0.0" -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/src/lib.rn: -------------------------------------------------------------------------------- 1 | pub fn get_name() { 2 | "b/lib" 3 | } 4 | -------------------------------------------------------------------------------- /editors/code/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/editors/code/assets/icon.png -------------------------------------------------------------------------------- /editors/code/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/editors/code/assets/logo.png -------------------------------------------------------------------------------- /scripts/book/types/bad_type_check.rn: -------------------------------------------------------------------------------- 1 | assert!(["hello", "world"] is String, "vectors should be strings"); 2 | -------------------------------------------------------------------------------- /tools/builder/README.md: -------------------------------------------------------------------------------- 1 | # builder 2 | 3 | A utility project for building and packaging Rune binaries. 4 | -------------------------------------------------------------------------------- /Rune.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "benches", 4 | "examples", 5 | "crates/rune", 6 | ] 7 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/src/main.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running a/bin") 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/items_imports/modules.rn: -------------------------------------------------------------------------------- 1 | mod foo; 2 | mod bar; 3 | 4 | dbg!(foo::number() + bar::number()); 5 | -------------------------------------------------------------------------------- /crates/rune/src/hashbrown/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use self::table::{IterRef, KeysRef, Table, ValuesRef}; 2 | mod table; 3 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/tests/fire/lib.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn check() { 2 | assert!(true) 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/primitives/copy.rn: -------------------------------------------------------------------------------- 1 | let a = 1; 2 | let b = a; 3 | a = 2; 4 | println!("{a}"); 5 | println!("{b}"); 6 | -------------------------------------------------------------------------------- /scripts/book/the_stack/call_and_add.rn: -------------------------------------------------------------------------------- 1 | fn foo(a, b) { 2 | a + b 3 | } 4 | 5 | let a = 3; 6 | foo(1, 2) + a 7 | -------------------------------------------------------------------------------- /book/src/string_literals.md: -------------------------------------------------------------------------------- 1 | You're probably looking for the section about [Template literals](template_literals.md). 2 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/src/main.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running b/bin") 3 | } 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/tests/fire/lib.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn check() { 2 | assert!(true) 3 | } 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/examples/simple.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running a/simple") 3 | } 4 | -------------------------------------------------------------------------------- /scripts/signal.rn: -------------------------------------------------------------------------------- 1 | println!("Waiting for ctrl-c"); 2 | signal::ctrl_c().await?; 3 | println!("Received ctrl-c event"); 4 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/slice.rs: -------------------------------------------------------------------------------- 1 | //! Types for working with slices. 2 | 3 | mod iter; 4 | pub(crate) use self::iter::Iter; 5 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/Rune.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "package-a", 4 | "nested/package-b" 5 | ] 6 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/examples/simple.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running b/simple") 3 | } 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/tests/fire/main.rn: -------------------------------------------------------------------------------- 1 | mod lib; 2 | 3 | #[test] 4 | fn fire() { 5 | lib::check(); 6 | } 7 | -------------------------------------------------------------------------------- /examples/examples/test/main.rn: -------------------------------------------------------------------------------- 1 | mod module; 2 | 3 | pub fn main() { 4 | println!("A simple example: {}", module::test()); 5 | } 6 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/tests/fire/main.rn: -------------------------------------------------------------------------------- 1 | mod lib; 2 | 3 | #[test] 4 | fn fire() { 5 | lib::check(); 6 | } 7 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/src/bin/named-executable.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running a/named-executable"); 3 | } 4 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # rune examples 2 | 3 | See: 4 | 5 | * [examples] - wide range of rust code examples. 6 | * [ace] - ace editor integration. -------------------------------------------------------------------------------- /scripts/book/compiler_guide/dead_code.rn: -------------------------------------------------------------------------------- 1 | return foo(); 2 | 3 | fn foo() { 4 | 2 5 | } 6 | 7 | fn bar() { 8 | 3 9 | } 10 | -------------------------------------------------------------------------------- /scripts/book/control_flow/conditional.rn: -------------------------------------------------------------------------------- 1 | let number = 3; 2 | 3 | if number < 5 { 4 | println!("The number is smaller than 5"); 5 | } 6 | -------------------------------------------------------------------------------- /scripts/book/items_imports/example_import.rn: -------------------------------------------------------------------------------- 1 | use std::iter::once; 2 | 3 | let it = once(0); 4 | 5 | dbg!(it.next()); 6 | dbg!(it.next()); 7 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/examples/multi-file-example/lib.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn get_name() { 2 | "a/multi-file-example" 3 | } 4 | -------------------------------------------------------------------------------- /site/content/posts/2023-10-10-my-project-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/site/content/posts/2023-10-10-my-project-cli.png -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/examples/multi-file-example/lib.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn get_name() { 2 | "b/multi-file-example" 3 | } 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/src/bin/named-executable.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("running b/named-executable"); 3 | } 4 | -------------------------------------------------------------------------------- /site/content/posts/2023-10-10-is-alphabetic-doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/site/content/posts/2023-10-10-is-alphabetic-doc.png -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/FiraSans-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/FiraSans-Medium.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/FiraSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/FiraSans-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/src/bin/multi-file-executable/main.rn: -------------------------------------------------------------------------------- 1 | mod module; 2 | 3 | pub fn main() { 4 | module::print_name(); 5 | } 6 | -------------------------------------------------------------------------------- /scripts/book/primitives/primitives.rn: -------------------------------------------------------------------------------- 1 | let a = String::from("Hello"); 2 | let b = a; 3 | a.push_str(" World"); 4 | println!("{a}"); 5 | println!("{b}"); 6 | -------------------------------------------------------------------------------- /site/templates/shortcodes/quote.html: -------------------------------------------------------------------------------- 1 |
2 | {{body}}
3 | {% if author %} 4 | -- {{ author }} 5 | {% endif %} 6 |
7 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceSerif4-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/SourceSerif4-Bold.woff2 -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/src/bin/multi-file-executable/main.rn: -------------------------------------------------------------------------------- 1 | mod module; 2 | 3 | pub fn main() { 4 | module::print_name(); 5 | } 6 | -------------------------------------------------------------------------------- /book/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["John-John Tedro"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "The Rune Programming Language" 7 | -------------------------------------------------------------------------------- /crates/rune-wasm/rune.js: -------------------------------------------------------------------------------- 1 | import wasm from "./Cargo.toml"; 2 | 3 | export async function init() { 4 | module = await wasm(); 5 | } 6 | 7 | export var module = null; -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceCodePro-It.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/SourceCodePro-It.ttf.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceCodePro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/SourceCodePro-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceSerif4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/SourceSerif4-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/tests/ui.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(miri))] 2 | 3 | #[test] 4 | fn ui() { 5 | let t = trybuild::TestCases::new(); 6 | t.compile_fail("tests/ui/*.rs"); 7 | } 8 | -------------------------------------------------------------------------------- /scripts/book/loops/loop_forever.rn: -------------------------------------------------------------------------------- 1 | use time::Duration; 2 | 3 | loop { 4 | println!("Hello forever!"); 5 | time::sleep(Duration::from_secs(1)).await; 6 | } 7 | -------------------------------------------------------------------------------- /scripts/fib.rn: -------------------------------------------------------------------------------- 1 | fn fib(n) { 2 | if n <= 1 { 3 | n 4 | } else { 5 | fib(n - 1) + fib(n - 2) 6 | } 7 | } 8 | 9 | dbg!(fib(15)); 10 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceCodePro-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/SourceCodePro-Semibold.woff2 -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/examples/multi-file-example/main.rn: -------------------------------------------------------------------------------- 1 | mod lib; 2 | 3 | pub fn main() { 4 | println!("running {}", lib::get_name()); 5 | } 6 | -------------------------------------------------------------------------------- /scripts/book/tuples/tuple_masquerade.rn: -------------------------------------------------------------------------------- 1 | let values = ("Now", "You", "See", "Me"); 2 | dbg!(values); 3 | 4 | values.2 = "Don't"; 5 | values.3 = "!"; 6 | dbg!(values); 7 | -------------------------------------------------------------------------------- /scripts/numbers.rn: -------------------------------------------------------------------------------- 1 | dbg!(0.223e2 + 2.to_f64()); 2 | dbg!((0.223e2).to_integer() + 2); 3 | 4 | let a = 42; 5 | 6 | if a is i64 { 7 | dbg!("a is an integer"); 8 | } 9 | -------------------------------------------------------------------------------- /book/src/deprecated.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | These are section of the book which have been deprecated for one reason or 4 | another, but we still want to provide links to. 5 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/NanumBarunGothic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/HEAD/crates/rune/src/doc/static/fonts/NanumBarunGothic-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/examples/multi-file-example/main.rn: -------------------------------------------------------------------------------- 1 | mod lib; 2 | 3 | pub fn main() { 4 | println!("running {}", lib::get_name()); 5 | } 6 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/src/bin/multi-file-executable/module/mod.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn print_name() { 2 | println!("running a/multi-file-executable") 3 | } 4 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/src/bin/multi-file-executable/module/mod.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn print_name() { 2 | println!("running b/multi-file-executable") 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/vectors/vectors_rev.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let values = ["Hello", 42]; 3 | 4 | for v in values.iter().rev() { 5 | println!("{}", v); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /crates/rune-wasm/module.js: -------------------------------------------------------------------------------- 1 | /// Hook used to construct an async sleep function. 2 | export function js_sleep(ms) { 3 | return new Promise(resolve => setTimeout(resolve, ms)); 4 | } 5 | -------------------------------------------------------------------------------- /examples/scripts/change_me.rn: -------------------------------------------------------------------------------- 1 | pub fn hello() { 2 | println!("{}: Hello world!", file!()); 3 | } 4 | 5 | pub fn goodbye() { 6 | println!("{}: Goodbye world!", file!()); 7 | } 8 | -------------------------------------------------------------------------------- /scripts/book/variables/variables.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let x = 5; 3 | println!("The value of x is: {}", x); 4 | x = 6; 5 | println!("The value of x is: {}", x); 6 | } 7 | -------------------------------------------------------------------------------- /site/content/rune.md: -------------------------------------------------------------------------------- 1 | +++ 2 | [extra] 3 | classes = "center" 4 | +++ 5 | 6 | ### The page you're looking for has been moved! 7 | 8 | You're probably looking for [The Rune Book](/book/). -------------------------------------------------------------------------------- /site/content/posts/_index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | sort_by = "date" 3 | paginate_by = 5 4 | paginate_path = "page" 5 | template = "posts.html" 6 | page_template = "post.html" 7 | render = true 8 | +++ 9 | -------------------------------------------------------------------------------- /scripts/book/instance_functions/missing_instance_fn.rn: -------------------------------------------------------------------------------- 1 | struct Foo; 2 | 3 | impl Foo { 4 | fn new() { 5 | Foo 6 | } 7 | } 8 | 9 | let foo = Foo::new(); 10 | foo.bar(); 11 | -------------------------------------------------------------------------------- /scripts/book/closures/basic_closure.rn: -------------------------------------------------------------------------------- 1 | fn work(op) { 2 | op(1, 2) 3 | } 4 | 5 | let n = 1; 6 | println!("Result: {}", work(|a, b| n + a + b)); 7 | println!("Result: {}", work(|a, b| n + a * b)); 8 | -------------------------------------------------------------------------------- /scripts/book/pattern_matching/bind.rn: -------------------------------------------------------------------------------- 1 | fn test_ignore(vector) { 2 | match vector { 3 | [_, b] => println!("Second item in vector is {}.", b), 4 | } 5 | } 6 | 7 | test_ignore([1, 2]); 8 | -------------------------------------------------------------------------------- /scripts/book/pattern_matching/ignore.rn: -------------------------------------------------------------------------------- 1 | fn test_ignore(vector) { 2 | match vector { 3 | [_, 2] => println!("Second item in vector is 2."), 4 | } 5 | } 6 | 7 | test_ignore([1, 2]); 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Cargo.lock 2 | /target 3 | /*.lua 4 | /*.py 5 | /scripts/test.rn 6 | /.vscode/spellright.dict 7 | *.rnc 8 | /.idea 9 | /flamegraph.svg 10 | /perf.data 11 | /perf.data.* 12 | /*.log 13 | -------------------------------------------------------------------------------- /scripts/book/control_flow/conditional_else.rn: -------------------------------------------------------------------------------- 1 | let number = 3; 2 | 3 | if number < 5 { 4 | println!("the number is smaller than 5"); 5 | } else { 6 | println!("the number is 5 or bigger"); 7 | } 8 | -------------------------------------------------------------------------------- /scripts/objects.rn: -------------------------------------------------------------------------------- 1 | let object = #{ "foo": 42 }; 2 | object["bar"] = object["foo"] + 1; 3 | object = #{ "foo": 1 }; 4 | let object = #{ "bar": 2 }; 5 | let a = object.get("foo"); 6 | 7 | dbg!(object, a); 8 | -------------------------------------------------------------------------------- /crates/rune/tests/tuples.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn modify_tuple() { 3 | let m = ("Now", "You", "See", "Me"); 4 | m.2 = "Don't"; 5 | m.3 = "!"; 6 | assert_eq!(`${m.0} ${m.1} ${m.2}${m.3}`, "Now You Don't!"); 7 | } 8 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/benches/multi-file-bench/main.rn: -------------------------------------------------------------------------------- 1 | mod collatz; 2 | 3 | #[bench] 4 | pub fn bench_collatz(b) { 5 | b.iter(|| { 6 | assert!(collatz::helper(1000, 0) == 111) 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/benches/multi-file-bench/main.rn: -------------------------------------------------------------------------------- 1 | mod collatz; 2 | 3 | #[bench] 4 | pub fn bench_collatz(b) { 5 | b.iter(|| { 6 | assert!(collatz::helper(1000, 0) == 111) 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /scripts/book/closures/closure_move.rn.fail: -------------------------------------------------------------------------------- 1 | fn work(op) { 2 | op(1, 2) 3 | } 4 | 5 | pub fn main() { 6 | let n = 1; 7 | println!("Result: {}", work(move |a, b| n + a + b)); 8 | assert!(!is_readable(n)); 9 | } 10 | -------------------------------------------------------------------------------- /scripts/generator_as_iter.rn: -------------------------------------------------------------------------------- 1 | fn foo() { 2 | yield 1; 3 | yield 2; 4 | yield 3; 5 | } 6 | 7 | let gen = foo(); 8 | 9 | while let Some(value) = gen.next() { 10 | println!("from generator: {}", value); 11 | } 12 | -------------------------------------------------------------------------------- /crates/rune/src/hir/interpreter.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::HashMap; 2 | use crate::runtime::Value; 3 | 4 | /// HIR interpreter. 5 | #[allow(unused)] 6 | pub(crate) struct Interpreter<'hir> { 7 | variables: HashMap<&'hir str, Value>, 8 | } 9 | -------------------------------------------------------------------------------- /scripts/book/generators/states.rn: -------------------------------------------------------------------------------- 1 | fn print_once() { 2 | let out = yield 1; 3 | println!("{:?}", out); 4 | 2 5 | } 6 | 7 | let printer = print_once(); 8 | dbg!(printer.resume(())); 9 | dbg!(printer.resume("John")); 10 | -------------------------------------------------------------------------------- /scripts/book/tuples/tuple_patterns.rn: -------------------------------------------------------------------------------- 1 | match ("test", 1) { 2 | ("test", n) => { 3 | dbg!("the first part was a number:", n); 4 | } 5 | _ => { 6 | dbg!("matched something we did not understand"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "macros.html" as macros %} 3 | 4 | {% block content %} 5 |
6 | {{ section.content | safe }} 7 |
8 | {% endblock content %} 9 | -------------------------------------------------------------------------------- /examples/ace/README.md: -------------------------------------------------------------------------------- 1 | # ace editor example 2 | 3 | Steps to run and build this example: 4 | 5 | ```sh 6 | cargo run -p rune-cli -- ace --output . 7 | python -m http.server 8 | ``` 9 | 10 | Then you can navigate to http://localhost:8000 -------------------------------------------------------------------------------- /scripts/book/variables/take_argument.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let object = #{ field: 1 }; 3 | let object2 = object; 4 | println!("field: {}", object.field); 5 | drop(object2); 6 | println!("field: {}", object.field); 7 | } 8 | -------------------------------------------------------------------------------- /site/templates/shortcodes/vm.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /crates/rune/tests/ui/install_with_compat.rs: -------------------------------------------------------------------------------- 1 | use rune::Any; 2 | 3 | // Generates a warning that the path should no longer be using a string literal. 4 | #[derive(Any)] 5 | #[rune(install_with = "foo::bar")] 6 | struct Struct {} 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /scripts/book/loops/loop_break.rn: -------------------------------------------------------------------------------- 1 | let counter = 0; 2 | 3 | let total = loop { 4 | counter = counter + 1; 5 | 6 | if counter > 10 { 7 | break counter; 8 | } 9 | }; 10 | 11 | println!("The final count is: {}", total); 12 | -------------------------------------------------------------------------------- /scripts/book/loops/while_loop.rn: -------------------------------------------------------------------------------- 1 | let value = 0; 2 | 3 | while value < 100 { 4 | if value >= 50 { 5 | break; 6 | } 7 | 8 | value = value + 1; 9 | } 10 | 11 | println!("The value is {}", value); // => The value is 50 12 | -------------------------------------------------------------------------------- /site/sass/_shortcodes.scss: -------------------------------------------------------------------------------- 1 | .youtube { 2 | & > iframe { 3 | width: 100%; 4 | height: 340px; 5 | } 6 | } 7 | 8 | .vimeo { 9 | & > iframe { 10 | width: 100%; 11 | height: 340px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/book/generators/error.rn: -------------------------------------------------------------------------------- 1 | fn print_once() { 2 | yield 1 3 | } 4 | 5 | let printer = print_once(); 6 | dbg!(printer); 7 | dbg!(printer.resume(())); 8 | dbg!(printer.resume("John")); 9 | dbg!(printer); 10 | dbg!(printer.resume(())); 11 | -------------------------------------------------------------------------------- /scripts/book/getting_started/dbg.rn: -------------------------------------------------------------------------------- 1 | fn function() { 2 | 42 3 | } 4 | 5 | let a = [1, 2, 3]; 6 | let b = '今'; 7 | let closure = || println!("Hello"); 8 | 9 | dbg!(a); 10 | dbg!(b); 11 | dbg!(function); 12 | dbg!(drop); 13 | dbg!(closure); 14 | -------------------------------------------------------------------------------- /crates/rune/src/item.rs: -------------------------------------------------------------------------------- 1 | //! Types related to items. 2 | //! 3 | //! Items are the global names for anything that can be addressed inside of 4 | //! Rune. 5 | 6 | #[doc(inline)] 7 | pub use rune_core::item::{Component, ComponentRef, IntoComponent, Item, ItemBuf}; 8 | -------------------------------------------------------------------------------- /scripts/book/functions/return_value.rn: -------------------------------------------------------------------------------- 1 | fn foo(condition) { 2 | if condition { 3 | "Hello" 4 | } else { 5 | 1 6 | } 7 | } 8 | 9 | pub fn main() { 10 | println!("{}", foo(true)); 11 | println!("{}", foo(false)); 12 | } 13 | -------------------------------------------------------------------------------- /crates/rune/tests/ui/install_with_compat.stderr: -------------------------------------------------------------------------------- 1 | error: String literals are no longer supported here, use a path like `foo :: bar` 2 | --> tests/ui/install_with_compat.rs:5:23 3 | | 4 | 5 | #[rune(install_with = "foo::bar")] 5 | | ^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /examples/examples/function_hash.rs: -------------------------------------------------------------------------------- 1 | use rune::{Hash, ItemBuf}; 2 | 3 | fn main() -> rune::support::Result<()> { 4 | println!("{}", Hash::type_hash(&ItemBuf::with_item(["Foo", "new"])?)); 5 | println!("{}", Hash::type_hash(["Foo", "new"])); 6 | Ok(()) 7 | } 8 | -------------------------------------------------------------------------------- /scripts/book/async/async_blocks.rn: -------------------------------------------------------------------------------- 1 | fn do_request(url) { 2 | async { 3 | Ok(http::get(url).await?.status()) 4 | } 5 | } 6 | 7 | let future = do_request("https://google.com"); 8 | let status = future.await?; 9 | println!("Status: {status}"); 10 | -------------------------------------------------------------------------------- /scripts/book/async/async_closure.rn: -------------------------------------------------------------------------------- 1 | fn do_request(url) { 2 | async || { 3 | Ok(http::get(url).await?.status()) 4 | } 5 | } 6 | 7 | let future = do_request("https://google.com"); 8 | let status = future().await?; 9 | println!("Status: {status}"); 10 | -------------------------------------------------------------------------------- /scripts/compile-fail/experimental_macro_error.rn.fail: -------------------------------------------------------------------------------- 1 | use std::experiments::stringy_math; 2 | 3 | pub fn main() { 4 | let a = 1; 5 | 6 | // This will error inside of the macro. 7 | let result = stringy_math! { 8 | doit a 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /book/src/advanced.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | 3 | This chapter is dedicated to the advanced topics of Rune. Here we will discuss 4 | the advanced and internal details of the language. This chapter is primarily 5 | targeted at people who want to understand Rune and Runestick in detail. 6 | -------------------------------------------------------------------------------- /editors/code/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | server/** 5 | node_modules/** 6 | src/** 7 | .gitignore 8 | .yarnrc 9 | webpack.config.js 10 | vsc-extension-quickstart.md 11 | **/tsconfig.json 12 | **/.eslintrc.json 13 | **/*.map 14 | **/*.ts 15 | -------------------------------------------------------------------------------- /scripts/book/closures/function_pointers.rn: -------------------------------------------------------------------------------- 1 | fn do_thing(op) { 2 | op(1, 2) 3 | } 4 | 5 | fn add(a, b) { 6 | a + b 7 | } 8 | 9 | fn sub(a, b) { 10 | a - b 11 | } 12 | 13 | println!("Result: {}", do_thing(add)); 14 | println!("Result: {}", do_thing(sub)); 15 | -------------------------------------------------------------------------------- /scripts/book/items_imports/inline_modules.rn: -------------------------------------------------------------------------------- 1 | mod foo { 2 | pub fn number() { 3 | 1 4 | } 5 | } 6 | 7 | mod bar { 8 | pub fn number() { 9 | 2 10 | } 11 | } 12 | 13 | pub fn main() { 14 | dbg!(foo::number() + bar::number()); 15 | } 16 | -------------------------------------------------------------------------------- /scripts/strings.rn: -------------------------------------------------------------------------------- 1 | let a = "foo"; 2 | 3 | let s = String::with_capacity(42); 4 | s.push_str(a); 5 | s.push('/'); 6 | s.push_str("bar"); 7 | 8 | dbg!(s, s.len(), s.capacity()); 9 | s.shrink_to_fit(); 10 | 11 | let b = s.into_bytes(); 12 | dbg!(b, b.len(), b.capacity()); 13 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_blocks.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_anonymous_type_precedence() { 5 | let out: i64 = rune! { 6 | fn a() { 1 } 7 | fn b() { return a(); fn a() { 2 } } 8 | a() + b() 9 | }; 10 | assert_eq!(out, 3); 11 | } 12 | -------------------------------------------------------------------------------- /crates/rune/tests/imports.rn: -------------------------------------------------------------------------------- 1 | mod a { 2 | pub struct Foo; 3 | } 4 | 5 | mod b { 6 | use c::Foo; 7 | use crate::a as c; 8 | pub fn test() { 9 | Foo is c::Foo 10 | } 11 | } 12 | 13 | #[test] 14 | fn module_import() { 15 | assert!(b::test()); 16 | } 17 | -------------------------------------------------------------------------------- /crates/rune/src/parse/traits.rs: -------------------------------------------------------------------------------- 1 | /// Advance a parser by a given amount. 2 | pub(crate) trait Advance { 3 | /// Error produced when advancing. 4 | type Error; 5 | 6 | /// Advance the parser by `n` tokens. 7 | fn advance(&mut self, n: usize) -> Result<(), Self::Error>; 8 | } 9 | -------------------------------------------------------------------------------- /scripts/book/control_flow/conditional_else_ifs.rn: -------------------------------------------------------------------------------- 1 | let number = 3; 2 | 3 | if number < 5 { 4 | println!("the number is smaller than 5"); 5 | } else if number == 5 { 6 | println!("the number is exactly 5"); 7 | } else { 8 | println!("the number is bigger than 5"); 9 | } 10 | -------------------------------------------------------------------------------- /scripts/book/control_flow/numbers_game.rn: -------------------------------------------------------------------------------- 1 | fn foo(n) { 2 | if n < 1 { 3 | return "less than one"; 4 | } 5 | 6 | "something else" 7 | } 8 | 9 | println!("{}", foo(0)); // => outputs: "less than one" 10 | println!("{}", foo(10)); // => outputs: "something else" 11 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/macro.html.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout}} 2 |

Macro {{literal module}}::{{name}}!(..)

Overview
3 | {{#if doc}}{{literal doc}}{{/if}} 4 | {{/layout}} 5 | -------------------------------------------------------------------------------- /crates/rune/tests/modules_inline.rn: -------------------------------------------------------------------------------- 1 | mod foo { 2 | pub fn number() { 3 | 1 4 | } 5 | } 6 | 7 | mod bar { 8 | pub fn number() { 9 | 2 10 | } 11 | } 12 | 13 | #[test] 14 | fn inline_modules() { 15 | assert_eq!(foo::number() + bar::number(), 3); 16 | } 17 | -------------------------------------------------------------------------------- /scripts/book/vectors/vectors.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let values = ["Hello", 42]; 3 | 4 | println!("{}", values[0]); 5 | println!("{}", values.1); // items in vectors can be accessed like tuple fields. 6 | 7 | for v in values { 8 | println!("{}", v); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/site/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "site" 3 | authors = ["John-John Tedro "] 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | reqwest = { version = "0.12.8", features = ["blocking"] } 9 | anyhow = "1.0.71" 10 | flate2 = "1.0.26" 11 | tar = "0.4.38" 12 | -------------------------------------------------------------------------------- /crates/rune/benches/fib.rn: -------------------------------------------------------------------------------- 1 | fn fib(n) { 2 | if n <= 1 { 3 | n 4 | } else { 5 | fib(n - 2) + fib(n - 1) 6 | } 7 | } 8 | 9 | #[bench] 10 | pub fn fib15(b) { 11 | b.iter(|| fib(15)); 12 | } 13 | 14 | #[bench] 15 | pub fn fib20(b) { 16 | b.iter(|| fib(20)); 17 | } 18 | -------------------------------------------------------------------------------- /scripts/book/variables/shared_ownership.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let object = #{ field: 1 }; 3 | let object2 = object; 4 | println!("{}", object.field); 5 | object2.field = 2; 6 | 7 | // Note: we changed `object2`, but read out `object` 8 | println!("{}", object.field); 9 | } 10 | -------------------------------------------------------------------------------- /site/templates/shortcodes/yt.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | -------------------------------------------------------------------------------- /crates/rune/tests/char.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn int_conversions() { 3 | let a = 'A'; 4 | let ai = char::to_i64(a); 5 | let result = char::from_i64(ai)?; 6 | assert_eq!(result, 'A'); 7 | 8 | let ai = 0x41; 9 | let result = char::from_i64(ai)?; 10 | assert_eq!(result, 'A'); 11 | } 12 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/tests/smoke.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn smoke() { 3 | assert!(true) 4 | } 5 | 6 | /// ```rune 7 | /// assert!(true); 8 | /// ``` 9 | fn doc_test() { 10 | } 11 | 12 | mod contained { 13 | #[test] 14 | fn smoulder() { 15 | assert!(true) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/rune/tests/function_pointers.rn: -------------------------------------------------------------------------------- 1 | fn do_thing(op) { 2 | op(1, 2) 3 | } 4 | 5 | fn add(a, b) { 6 | a + b 7 | } 8 | 9 | fn sub(a, b) { 10 | a - b 11 | } 12 | 13 | #[test] 14 | fn test_function_pointer() { 15 | assert_eq!(do_thing(add), 3); 16 | assert_eq!(do_thing(sub), -1); 17 | } 18 | -------------------------------------------------------------------------------- /tools/generate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generate" 3 | authors = ["John-John Tedro "] 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | serde = { version = "1.0.163", features = ["derive"] } 9 | serde_yaml = "0.9.21" 10 | genco = "0.17.6" 11 | anyhow = "1.0.71" 12 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/tests/smoke.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn smoke() { 3 | assert!(true) 4 | } 5 | 6 | /// ```rune 7 | /// assert!(true); 8 | /// ``` 9 | fn doc_test() { 10 | } 11 | 12 | mod contained { 13 | #[test] 14 | fn smoulder() { 15 | assert!(true) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/book/dynamic_types/greeting.rn: -------------------------------------------------------------------------------- 1 | struct Person { 2 | name, 3 | } 4 | 5 | impl Person { 6 | fn greet(self) { 7 | println!("Greetings from {}, and good luck with this section!", self.name); 8 | } 9 | } 10 | 11 | let person = Person { name: "John-John Tedro" }; 12 | 13 | person.greet(); 14 | -------------------------------------------------------------------------------- /crates/rune/src/modules/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macro support. 2 | 3 | pub mod builtin; 4 | 5 | use crate as rune; 6 | use crate::{ContextError, Module}; 7 | 8 | /// Macro support. 9 | #[rune::module(::std::macros)] 10 | pub fn module() -> Result { 11 | Module::from_meta(self::module__meta) 12 | } 13 | -------------------------------------------------------------------------------- /scripts/book/enums/count_numbers.rn: -------------------------------------------------------------------------------- 1 | fn count_numbers(limit) { 2 | let limit = limit.unwrap_or(10); 3 | 4 | for n in 0..limit { 5 | println!("Count: {}", n); 6 | } 7 | } 8 | 9 | println!("First count!"); 10 | count_numbers(None); 11 | 12 | println!("Second count!"); 13 | count_numbers(Some(2)); 14 | -------------------------------------------------------------------------------- /scripts/book/items_imports/item_keywords.rn: -------------------------------------------------------------------------------- 1 | mod first { 2 | pub fn number() { 3 | crate::number() + 2 4 | } 5 | } 6 | 7 | mod second { 8 | pub fn number() { 9 | super::first::number() + 4 10 | } 11 | } 12 | 13 | pub fn number() { 14 | 1 15 | } 16 | 17 | dbg!(self::second::number()); 18 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/benches/multi-file-bench/collatz.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn helper(value, steps) { 2 | if value == 1 { 3 | return steps; 4 | } 5 | 6 | if value % 2 == 0 { 7 | helper(value / 2, steps + 1) 8 | } else { 9 | helper(3 * value + 1, steps + 1) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /scripts/book/control_flow/first_match.rn: -------------------------------------------------------------------------------- 1 | let number = 3; 2 | 3 | match number { 4 | n if n < 5 => { 5 | println!("the number is smaller than 5"); 6 | } 7 | 5 => { 8 | println!("the number is exactly 5"); 9 | } 10 | n => { 11 | println!("the number is bigger than 5"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /site/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Ergo" 2 | description = "A simple blog Theme focused on writing, inspired by svbtle" 3 | license = "MIT" 4 | homepage = "https://github.com/insipx/Ergo" 5 | min_version = "0.4.1" 6 | demo = "https://ergo.liquidthink.net" 7 | 8 | [author] 9 | name = "Andrew Plaza" 10 | homepage = "https://liquidthink.net" 11 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/benches/multi-file-bench/collatz.rn: -------------------------------------------------------------------------------- 1 | pub(super) fn helper(value, steps) { 2 | if value == 1 { 3 | return steps; 4 | } 5 | 6 | if value % 2 == 0 { 7 | helper(value / 2, steps + 1) 8 | } else { 9 | helper(3 * value + 1, steps + 1) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /book/src/concepts.md: -------------------------------------------------------------------------------- 1 | # Concepts 2 | 3 | This chapter covers common concepts that appear in almost all programming 4 | languages, and how they work in Rune. 5 | 6 | Hopefully these should be familiar to anyone who's used imperative programming 7 | languages before. We'll try to take each concept and describe how they work with 8 | examples, one at a time. 9 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/index.html.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout}} 2 |

Index

3 | 4 | {{#if modules}} 5 |

Modules

6 | 7 | {{#each modules}} 8 |
{{this.item}}
9 | {{/each}} 10 | {{/if}} 11 | {{/layout}} 12 | -------------------------------------------------------------------------------- /scripts/book/try_operator/basic_try.rn: -------------------------------------------------------------------------------- 1 | fn checked_div_mod(a, b) { 2 | let div = a.checked_div(b)?; 3 | Some((div, a % b)) 4 | } 5 | 6 | if let Some((div, m)) = checked_div_mod(5, 2) { 7 | println!("Result: {}, {}", div, m); 8 | } 9 | 10 | if let Some((div, m)) = checked_div_mod(5, 0) { 11 | println!("Result: {}, {}", div, m); 12 | } 13 | -------------------------------------------------------------------------------- /tools/generate/README.md: -------------------------------------------------------------------------------- 1 | # generate 2 | 3 | A utility project for generating code for the rest of the project. 4 | 5 | This must be run with nightly, since it uses [Genco]. 6 | 7 | From the root of the project: 8 | 9 | ```bash 10 | cargo +nightly run --manifest-path tools/generate/Cargo.toml 11 | ``` 12 | 13 | [Genco]: https://github.com/udoprog/genco 14 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/env/std.rs: -------------------------------------------------------------------------------- 1 | use core::cell::Cell; 2 | 3 | use super::Env; 4 | 5 | std::thread_local!(static ENV: Cell = const { Cell::new(Env::null()) }); 6 | 7 | pub(super) fn rune_env_get() -> Env { 8 | ENV.with(|env| env.get()) 9 | } 10 | 11 | pub(super) fn rune_env_replace(env: Env) -> Env { 12 | ENV.with(|e| e.replace(env)) 13 | } 14 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_not_used.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_not_used() { 5 | let _: () = rune! { 6 | 0; 7 | 4.1; 8 | 'a'; 9 | b'a'; 10 | "Hello World"; 11 | b"Hello World"; 12 | [1, 2, 3]; 13 | (1, 2, 3, 4); 14 | #{"foo": 42, "bar": [1, 2, 3, 4]}; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /scripts/book/types/type_check.rn: -------------------------------------------------------------------------------- 1 | fn dynamic_type(n) { 2 | if n is String { 3 | "n is a String" 4 | } else if n is Vec { 5 | "n is a vector" 6 | } else { 7 | "n is unknown" 8 | } 9 | } 10 | 11 | println!("{}", dynamic_type("Hello")); 12 | println!("{}", dynamic_type([1, 2, 3, 4])); 13 | println!("{}", dynamic_type(42)); 14 | -------------------------------------------------------------------------------- /scripts/book/types/type_check_patterns.rn: -------------------------------------------------------------------------------- 1 | fn dynamic_type(n) { 2 | match n { 3 | n if n is String => "n is a String", 4 | n if n is Vec => "n is a vector", 5 | _ => "n is unknown", 6 | } 7 | } 8 | 9 | println!("{}", dynamic_type("Hello")); 10 | println!("{}", dynamic_type([1, 2, 3, 4])); 11 | println!("{}", dynamic_type(42)); 12 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/budget/std.rs: -------------------------------------------------------------------------------- 1 | use core::cell::Cell; 2 | 3 | std::thread_local!(static BUDGET: Cell = const { Cell::new(usize::MAX) }); 4 | 5 | pub(super) fn rune_budget_get() -> usize { 6 | BUDGET.with(|tls| tls.get()) 7 | } 8 | 9 | pub(super) fn rune_budget_replace(value: usize) -> usize { 10 | BUDGET.with(|tls| tls.replace(value)) 11 | } 12 | -------------------------------------------------------------------------------- /scripts/book/variables/is_readable.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let object = #{ field: 1 }; 3 | let object2 = object; 4 | println!("field: {}", object.field); 5 | drop(object2); 6 | 7 | if is_readable(object) { 8 | println!("field: {}", object.field); 9 | } else { 10 | println!("object is no longer readable 😢"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/rune/src/tests/bug_428.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | pub fn test_bug_428() { 5 | let (a, b): (String, String) = rune! { 6 | let a = format!("{:>} = {:>}", "AB", 0x1234); 7 | let b = format!("{:>} = {:08}", "AB", 0x1234); 8 | (a, b) 9 | }; 10 | 11 | assert_eq!(a, "AB = 4660"); 12 | assert_eq!(b, "AB = 00004660"); 13 | } 14 | -------------------------------------------------------------------------------- /crates/rune/tests/modules_vis.rn: -------------------------------------------------------------------------------- 1 | mod first { 2 | pub fn number() { 3 | crate::number() + 2 4 | } 5 | } 6 | 7 | mod second { 8 | pub fn number() { 9 | super::first::number() + 4 10 | } 11 | } 12 | 13 | pub fn number() { 14 | 1 15 | } 16 | 17 | #[test] 18 | fn item_keywords() { 19 | assert_eq!(self::second::number(), 7); 20 | } 21 | -------------------------------------------------------------------------------- /scripts/book/generators/fib_generator.rn: -------------------------------------------------------------------------------- 1 | fn fib() { 2 | let a = 0; 3 | let b = 1; 4 | 5 | loop { 6 | yield a; 7 | let c = a + b; 8 | a = b; 9 | b = c; 10 | } 11 | } 12 | 13 | let g = fib(); 14 | 15 | while let Some(n) = g.next() { 16 | println!("{n}"); 17 | 18 | if n > 100 { 19 | break; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | 4 | members = [ 5 | "crates/*", 6 | "examples", 7 | "benches", 8 | "tools/*", 9 | "no-std", 10 | ] 11 | 12 | default-members = [ 13 | "crates/*", 14 | "examples", 15 | "benches", 16 | "tools/site", 17 | "tools/builder", 18 | ] 19 | 20 | [profile.bench] 21 | lto = false 22 | debug = true 23 | -------------------------------------------------------------------------------- /crates/rune-macros/tests/derive.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use rune::T; 4 | use rune_macros::*; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] 7 | struct SomeThing { 8 | eq: T![=], 9 | } 10 | 11 | #[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] 12 | struct EqValue { 13 | eq: rune::ast::Eq, 14 | value: T, 15 | } 16 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_assign_exprs.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_assign_assign_exprs() { 5 | let out: (i64, (), ()) = eval( 6 | r#" 7 | let a = #{b: #{c: #{d: 1}}}; 8 | let b = 2; 9 | let c = 3; 10 | 11 | c = b = a.b.c = 4; 12 | (a.b.c, b, c) 13 | "#, 14 | ); 15 | assert_eq!(out, (4, (), ())); 16 | } 17 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_async_block.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_async_block() { 5 | let out: i64 = rune! { 6 | async fn foo(value) { 7 | let output = value.await; 8 | output 9 | } 10 | 11 | let value = 42; 12 | foo(async { value }).await / foo(async { 2 }).await 13 | }; 14 | assert_eq!(out, 21); 15 | } 16 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/hint.rs: -------------------------------------------------------------------------------- 1 | cfg_if! { 2 | if #[cfg(rune_nightly)] { 3 | pub(crate) use core::intrinsics::{likely, unlikely, assume}; 4 | } else { 5 | pub(crate) use core::convert::{identity as likely, identity as unlikely}; 6 | 7 | #[inline(always)] 8 | pub(crate) fn assume(_: bool) { 9 | // do nothing 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scripts/book/async/async_http.rn: -------------------------------------------------------------------------------- 1 | let a = http::get("https://google.com"); 2 | let b = http::get("https://amazon.com"); 3 | 4 | loop { 5 | let res = select { 6 | res = a => res?, 7 | res = b => res?, 8 | }; 9 | 10 | match res { 11 | () => break, 12 | result => { 13 | println!("{}", result.status()); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/book/generators/bootup.rn: -------------------------------------------------------------------------------- 1 | fn printer() { 2 | loop { 3 | println!("waiting for value..."); 4 | let out = yield; 5 | println!("{out:?}"); 6 | } 7 | } 8 | 9 | let printer = printer(); 10 | 11 | println!("firing off the printer..."); 12 | printer.resume(()); 13 | println!("ready to go!"); 14 | 15 | printer.resume("John"); 16 | printer.resume((1, 2, 3)); 17 | -------------------------------------------------------------------------------- /tools/builder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "builder" 3 | authors = ["John-John Tedro "] 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0.71" 9 | regex = { version = "1.8.1", default-features = false, features = ["std", "unicode-perl"] } 10 | zip = "2.2.0" 11 | flate2 = { version = "1.0.26", features = ["zlib"], default-features = false } 12 | -------------------------------------------------------------------------------- /crates/rune-wasm/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import rust from "@wasm-tool/rollup-plugin-rust"; 2 | 3 | export default { 4 | input: "rune.js", 5 | output: { 6 | dir: "../../site/static/js", 7 | format: "iife", 8 | name: "rune", 9 | sourcemap: true, 10 | }, 11 | plugins: [ 12 | rust({ 13 | serverPath: "/js/" 14 | }), 15 | ], 16 | }; -------------------------------------------------------------------------------- /scripts/book/objects/objects.rn: -------------------------------------------------------------------------------- 1 | let values = #{}; 2 | values["first"] = "bar"; 3 | values["second"] = 42; 4 | 5 | dbg!(values["first"]); 6 | dbg!(values.second); // items be accessed like struct fields. 7 | 8 | if let Some(key) = values.get("not a key") { 9 | dbg!(key); 10 | } else { 11 | println!("key did not exist"); 12 | } 13 | 14 | for entry in values { 15 | dbg!(entry); 16 | } 17 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_fn.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_fn_const_async() { 7 | assert_errors! { 8 | r#"pub const async fn main() {}"#, 9 | span!(4, 15), FnConstAsyncConflict 10 | }; 11 | 12 | assert_errors! { 13 | r#"pub const fn main() { yield true }"#, 14 | span!(22, 32), YieldInConst 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /crates/rune/tests/int_ops.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn int_ops() { 3 | assert_eq!(1.min(2), 1); 4 | assert_eq!(std::i64::min(1, 2), 1); 5 | 6 | assert_eq!(1.max(2), 2); 7 | assert_eq!(std::i64::max(1, 2), 2); 8 | 9 | assert_eq!((-10).abs(), 10); 10 | assert_eq!(std::i64::abs(-10), 10); 11 | 12 | assert_eq!((12).pow(3), 1728); 13 | assert_eq!(std::i64::pow(12, 3), 1728); 14 | } 15 | -------------------------------------------------------------------------------- /scripts/book/generators/send_values.rn: -------------------------------------------------------------------------------- 1 | fn printer() { 2 | let collected = []; 3 | 4 | for _ in 0..2 { 5 | let out = yield; 6 | println!("{:?}", out); 7 | collected.push(out); 8 | } 9 | 10 | assert_eq!(collected, ["John", (1, 2, 3)]); 11 | } 12 | 13 | let printer = printer(); 14 | printer.resume(()); 15 | printer.resume("John"); 16 | printer.resume((1, 2, 3)); 17 | -------------------------------------------------------------------------------- /scripts/book/pattern_matching/rest_pattern.rn: -------------------------------------------------------------------------------- 1 | let value = #{ a: 0, b: 1 }; 2 | 3 | let matched = match value { 4 | // this doesn't match, because a pattern without a rest pattern in it 5 | // must match exactly. 6 | #{ a } => false, 7 | // this matches, because it only requires `a` to be present. 8 | #{ a, .. } => true, 9 | }; 10 | 11 | assert!(matched, "rest pattern matched"); 12 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Error; 2 | use crate::vec::Vec; 3 | 4 | #[test] 5 | fn test_vec_macro() -> Result<(), Error> { 6 | let vec: Vec = try_vec![1, 2, 3]; 7 | assert_eq!(vec, [1, 2, 3]); 8 | 9 | let vec: Vec = try_vec![1; 3]; 10 | assert_eq!(vec, [1, 1, 1]); 11 | 12 | let vec: Vec = try_vec![]; 13 | assert!(vec.is_empty()); 14 | Ok(()) 15 | } 16 | -------------------------------------------------------------------------------- /crates/rune/src/modules/hash.rs: -------------------------------------------------------------------------------- 1 | //! Hashing types. 2 | 3 | use crate as rune; 4 | use crate::runtime::Hasher; 5 | use crate::{ContextError, Module}; 6 | 7 | /// Hashing types. 8 | #[rune::module(::std::hash)] 9 | pub fn module() -> Result { 10 | #[allow(unused_mut)] 11 | let mut module = Module::from_meta(self::module__meta)?; 12 | module.ty::()?; 13 | Ok(module) 14 | } 15 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/iter/mod.rs: -------------------------------------------------------------------------------- 1 | //! Composable external iteration. 2 | 3 | pub use self::ext::IteratorExt; 4 | mod ext; 5 | 6 | pub use self::try_cloned::TryCloned; 7 | mod try_cloned; 8 | 9 | pub use self::try_extend::TryExtend; 10 | mod try_extend; 11 | 12 | pub use self::try_from_iterator::{TryFromIterator, TryFromIteratorIn}; 13 | mod try_from_iterator; 14 | 15 | pub use self::join::TryJoin; 16 | pub(crate) mod join; 17 | -------------------------------------------------------------------------------- /crates/rune/src/hir/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | 4 | mod arena; 5 | pub(crate) use self::arena::Arena; 6 | 7 | mod hir; 8 | pub(crate) use self::hir::*; 9 | 10 | pub(crate) mod lowering; 11 | pub(crate) mod lowering2; 12 | 13 | pub(crate) mod scopes; 14 | pub(crate) use self::scopes::Scopes; 15 | 16 | pub(crate) mod interpreter; 17 | 18 | mod ctxt; 19 | pub(crate) use self::ctxt::Ctxt; 20 | use self::ctxt::Needs; 21 | -------------------------------------------------------------------------------- /crates/rune/src/languageserver/fs.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io; 3 | use std::path::Path; 4 | 5 | /// Test if the given path is a file. 6 | pub(super) fn is_file

(path: P) -> io::Result 7 | where 8 | P: AsRef, 9 | { 10 | match fs::metadata(path) { 11 | Ok(m) => Ok(m.is_file()), 12 | Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(false), 13 | Err(e) => Err(e), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/iter/join.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::Allocator; 2 | use crate::error::Error; 3 | 4 | /// Helper trait for joining iterators. 5 | pub trait TryJoin 6 | where 7 | Self: Sized, 8 | A: Allocator, 9 | { 10 | /// Try to join the given value in the given allocator. 11 | fn try_join_in(iter: I, sep: S, alloc: A) -> Result 12 | where 13 | I: IntoIterator; 14 | } 15 | -------------------------------------------------------------------------------- /crates/rune/src/tests/esoteric_impls.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn deny_self_impl() { 7 | assert_errors! { 8 | r#" 9 | struct Foo; 10 | 11 | impl Foo { 12 | fn a() { 13 | impl Self { 14 | fn b(self) {} 15 | } 16 | } 17 | } 18 | "#, 19 | span!(83, 87), UnsupportedSelfType, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/rune/src/languageserver/tests.rs: -------------------------------------------------------------------------------- 1 | use super::Code; 2 | 3 | #[test] 4 | fn test_code() { 5 | let code: Code = serde_json::from_str("-1").unwrap(); 6 | assert_eq!(code, Code::Unknown(-1)); 7 | assert_eq!(serde_json::to_string(&code).unwrap(), "-1"); 8 | 9 | let code: Code = serde_json::from_str("-32601").unwrap(); 10 | assert_eq!(code, Code::MethodNotFound); 11 | assert_eq!(serde_json::to_string(&code).unwrap(), "-32601"); 12 | } 13 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_expr_assign.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn assign_expr() { 7 | assert_parse!(r#"let var = 1; var = 42;"#); 8 | 9 | assert_errors! { 10 | r#"1 = 42;"#, 11 | span!(0, 6), UnsupportedAssignExpr 12 | }; 13 | } 14 | 15 | #[test] 16 | fn mut_let() { 17 | assert_errors! { 18 | r#"let mut var = 1;"#, 19 | span!(4, 7), UnsupportedMut 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/package-a/benches/collatz.rn: -------------------------------------------------------------------------------- 1 | fn collatz_helper(value, steps) { 2 | if value == 1 { 3 | return steps; 4 | } 5 | 6 | if value % 2 == 0 { 7 | collatz_helper(value / 2, steps + 1) 8 | } else { 9 | collatz_helper(3 * value + 1, steps + 1) 10 | } 11 | } 12 | 13 | #[bench] 14 | pub fn collatz(b) { 15 | b.iter(|| { 16 | assert!(collatz_helper(1000, 0) == 111) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /crates/rune/src/tests/workspace/nested/package-b/benches/collatz.rn: -------------------------------------------------------------------------------- 1 | fn collatz_helper(value, steps) { 2 | if value == 1 { 3 | return steps; 4 | } 5 | 6 | if value % 2 == 0 { 7 | collatz_helper(value / 2, steps + 1) 8 | } else { 9 | collatz_helper(3 * value + 1, steps + 1) 10 | } 11 | } 12 | 13 | #[bench] 14 | pub fn collatz(b) { 15 | b.iter(|| { 16 | assert!(collatz_helper(1000, 0) == 111) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /crates/rune/src/cli/languageserver.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | 3 | use crate::languageserver; 4 | use crate::{Context, Options}; 5 | 6 | pub(super) async fn run(context: Context) -> Result<()> { 7 | let options = Options::from_default_env()?; 8 | 9 | let ls = languageserver::builder() 10 | .with_context(context) 11 | .with_options(options) 12 | .with_stdio() 13 | .build()?; 14 | 15 | ls.run().await?; 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /crates/rune/tests/const.rn: -------------------------------------------------------------------------------- 1 | const fn foo(n) { 2 | n + 1 3 | } 4 | 5 | const VALUE1 = foo(1); 6 | 7 | const VALUE2 = { 8 | foo(2) + 4 9 | }; 10 | 11 | const VALUE3 = { 12 | foo(8) + 16 13 | }; 14 | 15 | #[test] 16 | fn const_value() { 17 | assert_eq!(VALUE1, 2); 18 | assert_eq!(VALUE2, 7); 19 | assert_eq!(VALUE3, 25); 20 | assert_eq!(const { VALUE1 + VALUE2 + VALUE3 }, 34); 21 | assert_eq!(format!(const { "{" + "}" }, 10), "10"); 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune/tests/reordering.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn test_stmt_reordering() { 3 | let len = 0; 4 | let value = String::from("Hello"); 5 | len = value.len(); 6 | let value2 = drop(value); 7 | 8 | assert_eq!(len, 5); 9 | } 10 | 11 | #[test] 12 | fn test_const_stmt_reordering() { 13 | const fn foo() { 14 | let n = 0; 15 | n = 1; 16 | let n = 2; 17 | n 18 | } 19 | 20 | let n = foo(); 21 | assert_eq!(n, 2); 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_test_mod.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_nested_mods() { 5 | let out: i64 = rune! { 6 | pub mod hello { 7 | pub mod inner { 8 | pub fn test() { 9 | 2 10 | } 11 | } 12 | 13 | pub fn test() { 14 | 1 + inner::test() 15 | } 16 | } 17 | 18 | hello::test() 19 | }; 20 | assert_eq!(out, 3); 21 | } 22 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | authors = ["John-John Tedro "] 4 | edition = "2021" 5 | publish = false 6 | 7 | [features] 8 | full = ["rune-modules/full"] 9 | default = ["full"] 10 | 11 | [dependencies] 12 | rune = { path = "../crates/rune" } 13 | rune-modules = { path = "../crates/rune-modules" } 14 | 15 | tokio = { version = "1.28.1", features = ["macros"] } 16 | notify = "8.0.0" 17 | anyhow = "1.0.82" 18 | pin-project = "1.1.5" 19 | -------------------------------------------------------------------------------- /benches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-benches" 3 | edition = "2021" 4 | publish = false 5 | 6 | [dependencies] 7 | rune = { path = "../crates/rune", features = ["bench", "capture-io"] } 8 | rhai = "1.21.0" 9 | 10 | tokio = { version = "1.28.1", features = ["macros"] } 11 | criterion = "0.6.0" 12 | anyhow = "1.0.71" 13 | futures-executor = "0.3.28" 14 | 15 | [[bench]] 16 | name = "main" 17 | harness = false 18 | 19 | [[bench]] 20 | name = "comparison" 21 | harness = false 22 | -------------------------------------------------------------------------------- /crates/rune/src/tests/bug_454.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | /// See https://github.com/rune-rs/rune/issues/454 4 | #[test] 5 | pub fn test_bug_454() { 6 | let _: () = rune! { 7 | struct Test; 8 | 9 | fn call(a, b) { 10 | a + b 11 | } 12 | 13 | impl Test { 14 | fn call(self) { 15 | call(1, 2) 16 | } 17 | } 18 | 19 | let test = Test; 20 | assert_eq!(test.call(), 3); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /book/src/try_operator.md: -------------------------------------------------------------------------------- 1 | # Try operator 2 | 3 | The try operator (`?`) is a control flow operator which causes a function to 4 | return early in case the value being tried over has a certain value. 5 | 6 | For `Option`, this causes the function to return if it has the `Option::None` 7 | variant. 8 | 9 | ```rune 10 | {{#include ../../scripts/book/try_operator/basic_try.rn}} 11 | ``` 12 | 13 | ```text 14 | $> cargo run -- run scripts/book/try_operator/basic_try.rn 15 | Result: 2, 1 16 | ``` 17 | -------------------------------------------------------------------------------- /site/templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "macros.html" as macros %} 3 | 4 | {% block header %} 5 |

8 | {% endblock header %} 9 | 10 | {% block content %} 11 |
12 | {{ page.content | safe }} 13 |
14 | {% endblock content %} 15 | -------------------------------------------------------------------------------- /book/src/streams.md: -------------------------------------------------------------------------------- 1 | # Streams 2 | 3 | Streams are the asynchronous version of [Generators](./generators.md). 4 | 5 | They have almost identical `next` and `resume` functions, but each must be used 6 | with `.await`, and we are now allowed to use asynchronous functions inside of 7 | the generator. 8 | 9 | ```rune 10 | {{#include ../../scripts/book/streams/basic_stream.rn}} 11 | ``` 12 | 13 | ```text 14 | $> cargo run -- run scripts/book/streams/basic_stream.rn 15 | 200 OK 16 | 200 OK 17 | ``` 18 | -------------------------------------------------------------------------------- /editors/code/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright the [rust-analyzer](https://github.com/rust-lang/rust-analyzer/tree/master/editors/code) authors 2 | Copyright 2018-2022 the Rune authors 3 | 4 | The Rune Visual Studio Code Exstension is heavily based on the 5 | [rust-analyzer](https://github.com/rust-lang/rust-analyzer/tree/master/editors/code) Visual Studio Code Exstension 6 | and distributed under the terms of both the MIT license and the Apache License (Version 2.0). 7 | 8 | See LICENSE-APACHE and LICENSE-MIT for details. -------------------------------------------------------------------------------- /crates/rune-alloc/src/fmt/impls.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::Allocator; 2 | use crate::error::Error; 3 | use crate::vec::Vec; 4 | 5 | use super::TryWrite; 6 | 7 | /// [`TryWrite`] is implemented for `Vec` by appending to the vector. The 8 | /// vector will grow as needed. 9 | impl TryWrite for Vec 10 | where 11 | A: Allocator, 12 | { 13 | #[inline] 14 | fn try_write_str(&mut self, s: &str) -> Result<(), Error> { 15 | self.try_extend_from_slice(s.as_bytes()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/book/streams/basic_stream.rn: -------------------------------------------------------------------------------- 1 | async fn send_requests(list) { 2 | let client = http::Client::new(); 3 | 4 | let do_request = async |url| { 5 | Ok(client.get(url).send().await?.status()) 6 | }; 7 | 8 | for url in list { 9 | yield do_request(url).await; 10 | } 11 | } 12 | 13 | let requests = send_requests(["https://google.com", "https://amazon.com"]); 14 | 15 | while let Some(status) = requests.next().await.transpose()? { 16 | println!("{}", status); 17 | } 18 | -------------------------------------------------------------------------------- /crates/rune/src/ast/to_ast.rs: -------------------------------------------------------------------------------- 1 | use crate::compile::Result; 2 | 3 | use super::{Expectation, Kind, Span}; 4 | 5 | /// Helper trait to coerce a kind into ast. 6 | pub(crate) trait ToAst 7 | where 8 | Self: Sized, 9 | { 10 | /// Coerce a value into ast. 11 | fn to_ast(span: Span, kind: Kind) -> Result; 12 | 13 | /// Test if the given ast matches. 14 | fn matches(kind: &Kind) -> bool; 15 | 16 | /// Get the expectation for this type. 17 | fn into_expectation() -> Expectation; 18 | } 19 | -------------------------------------------------------------------------------- /scripts/book/pattern_matching/fast_cars.rn: -------------------------------------------------------------------------------- 1 | fn describe_car(car) { 2 | match car { 3 | #{ "make": year, .. } if year < 1950 => "What, where did you get that?", 4 | #{ "model": "Ford", "make": year, .. } if year >= 2000 => "Pretty fast!", 5 | _ => "Can't tell 😞", 6 | } 7 | } 8 | 9 | println!("{}", describe_car(#{"model": "Ford", "make": 2000})); 10 | println!("{}", describe_car(#{"model": "Honda", "make": 1980})); 11 | println!("{}", describe_car(#{"model": "Volvo", "make": 1910})); 12 | -------------------------------------------------------------------------------- /crates/rune-wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rune-wasm", 3 | "version": "0.0.0", 4 | "description": "A WASM module for the Rune Language, an embeddable dynamic programming language for Rust.", 5 | "main": "rollup.config.mjs", 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "@wasm-tool/rollup-plugin-rust": "^2.3.3", 9 | "rollup": "^3.29.5" 10 | }, 11 | "scripts": { 12 | "build": "rollup -c" 13 | }, 14 | "author": "John-John Tedro ", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_result.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_result() { 5 | let out: i64 = rune!(match Err("err") { 6 | Err("err") => 1, 7 | _ => 2, 8 | }); 9 | assert_eq!(out, 1); 10 | 11 | let out: i64 = rune!(match Err("err") { 12 | Ok("ok") => 1, 13 | _ => 2, 14 | }); 15 | assert_eq!(out, 2); 16 | 17 | let out: i64 = rune!(match Ok("ok") { 18 | Ok("ok") => 1, 19 | _ => 2, 20 | }); 21 | assert_eq!(out, 1); 22 | } 23 | -------------------------------------------------------------------------------- /book/src/dynamic_types.md: -------------------------------------------------------------------------------- 1 | # Dynamic types 2 | 3 | Dynamic types are types which can be defined and used solely within a Rune 4 | script. They provide the ability to structure data and associate functions with 5 | it. 6 | 7 | The following is a quick example of a `struct`: 8 | 9 | ```rune 10 | {{#include ../../scripts/book/dynamic_types/greeting.rn}} 11 | ``` 12 | 13 | ```text 14 | $> cargo run -- run scripts/book/dynamic_types/greeting.rn 15 | Greetings from John-John Tedro, and good luck with this section! 16 | ``` 17 | -------------------------------------------------------------------------------- /crates/rune-alloc/tools/import.ps1: -------------------------------------------------------------------------------- 1 | $Path = "D:\Repo\rust" 2 | Copy-Item $Path\library\alloc\src\collections\btree\ -Destination third-party -Recurse -Force 3 | Copy-Item $Path\library\alloc\src\vec\ -Destination third-party -Recurse -Force 4 | Copy-Item $Path\library\alloc\src\collections\vec_deque\ -Destination third-party -Recurse -Force 5 | Copy-Item $Path\library\alloc\src\testing\ -Destination third-party -Recurse -Force 6 | 7 | $Path = "D:\Repo\hashbrown" 8 | Copy-Item $Path\src\ -Destination third-party\hashbrown -Recurse -Force 9 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/steps_between.rs: -------------------------------------------------------------------------------- 1 | pub(crate) trait StepsBetween { 2 | fn steps_between(start: Self, end: Self) -> Option; 3 | } 4 | 5 | impl StepsBetween for i64 { 6 | #[inline] 7 | fn steps_between(start: Self, end: Self) -> Option { 8 | usize::try_from(end.checked_sub(start)?).ok() 9 | } 10 | } 11 | 12 | impl StepsBetween for u64 { 13 | #[inline] 14 | fn steps_between(start: Self, end: Self) -> Option { 15 | usize::try_from(end.checked_sub(start)?).ok() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /no-std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "no-std" 3 | authors = ["John-John Tedro "] 4 | edition = "2021" 5 | publish = false 6 | 7 | [features] 8 | std = ["rune/std"] 9 | 10 | [dependencies] 11 | rune = { path = "../crates/rune", default-features = false, features = ["alloc"] } 12 | wee_alloc = "0.4.5" 13 | # Pull in your own critical-section implementation. 14 | # See: https://github.com/rust-embedded/critical-section/tree/main#usage-in-no-std-binaries 15 | critical-section = { version = "1.2.0", default-features = false } 16 | -------------------------------------------------------------------------------- /crates/rune/src/doc/build/js.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::{self, String}; 2 | 3 | /// Encode `string` as part of a quoted javascript string. 4 | pub(crate) fn encode_quoted(out: &mut String, string: &str) -> alloc::Result<()> { 5 | for c in string.chars() { 6 | let s = match c { 7 | '\\' => "\\\\", 8 | '\"' => "\\\"", 9 | c => { 10 | out.try_push(c)?; 11 | continue; 12 | } 13 | }; 14 | 15 | out.try_push_str(s)?; 16 | } 17 | 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_warnings.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use diagnostics::WarningDiagnosticKind::*; 4 | 5 | #[test] 6 | fn test_let_pattern_might_panic() { 7 | assert_warnings! { 8 | "let [0, 1, 3] = [];", 9 | span!(4, 13), LetPatternMightPanic { context: Some(span!(0, 19)), .. } 10 | }; 11 | } 12 | 13 | #[test] 14 | fn test_template_without_variables() { 15 | assert_warnings! { 16 | "`Hello World`", 17 | span!(0, 13), TemplateWithoutExpansions { context: Some(span!(0, 13)), .. } 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /scripts/primes.rn: -------------------------------------------------------------------------------- 1 | const MAX_NUMBER_TO_CHECK = 10_000; 2 | 3 | let prime_mask = []; 4 | 5 | prime_mask.resize(MAX_NUMBER_TO_CHECK, true); 6 | 7 | prime_mask[0] = false; 8 | prime_mask[1] = false; 9 | 10 | let total_primes_found = 0; 11 | 12 | for p in 2..MAX_NUMBER_TO_CHECK { 13 | if prime_mask[p] { 14 | total_primes_found += 1; 15 | let i = 2 * p; 16 | 17 | while i < MAX_NUMBER_TO_CHECK { 18 | prime_mask[i] = false; 19 | i += p; 20 | } 21 | } 22 | } 23 | 24 | dbg!(total_primes_found); 25 | -------------------------------------------------------------------------------- /editors/code/src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /crates/rune/src/compile/v1/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod assemble; 2 | pub(crate) use self::assemble::Ctxt; 3 | 4 | mod breaks; 5 | pub(crate) use self::breaks::{Break, Breaks}; 6 | 7 | mod scopes; 8 | pub(crate) use self::scopes::Scopes; 9 | use self::scopes::{ScopeHandle, ScopeId}; 10 | 11 | mod slots; 12 | use self::slots::Slots; 13 | 14 | mod needs; 15 | use self::needs::{Address, Any, Needs}; 16 | 17 | mod slab; 18 | use self::slab::Slab; 19 | 20 | mod linear; 21 | use self::linear::Linear; 22 | 23 | mod display_named; 24 | use self::display_named::DisplayNamed; 25 | -------------------------------------------------------------------------------- /crates/rune/src/modules/i64.rs: -------------------------------------------------------------------------------- 1 | //! Integers. 2 | 3 | use core::cmp::Ordering; 4 | use core::num::ParseIntError; 5 | 6 | use crate as rune; 7 | use crate::alloc::string::TryToString; 8 | use crate::{ContextError, Module}; 9 | 10 | /// Signed integers. 11 | /// 12 | /// This provides methods for computing over and parsing 64-bit signed integers. 13 | #[rune::module(::std::i64)] 14 | pub fn module() -> Result { 15 | let mut m = Module::from_meta(self::module__meta)?; 16 | signed!(m, i64); 17 | Ok(m) 18 | } 19 | 20 | signed_fns!(i64); 21 | -------------------------------------------------------------------------------- /crates/rune/src/tests/continue_.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_continue_not_in_loop() { 7 | assert_errors! { 8 | r#"pub fn main() { continue }"#, 9 | span!(16, 24), ContinueUnsupported, 10 | }; 11 | } 12 | 13 | #[test] 14 | fn test_continue_missing_label() { 15 | assert_errors! { 16 | r#"pub fn main() { 'existing: loop { loop { continue 'missing; } } }"#, 17 | span!(41, 58), MissingLabel { label } => { 18 | assert_eq!(&*label, "missing"); 19 | } 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /scripts/book/pattern_matching/big_match.rn: -------------------------------------------------------------------------------- 1 | fn match_input(n) { 2 | match n { 3 | 1 => println!("The number one."), 4 | n if n is i64 => println!("Another number: {}.", n), 5 | [1, 2, n, ..] => println!("A vector starting with one and two, followed by {}.", n), 6 | "one" => println!("One, but this time as a string."), 7 | _ => println!("Something else. Can I go eat now?"), 8 | } 9 | } 10 | 11 | match_input(1); 12 | match_input(2); 13 | match_input([1, 2, 42, 84]); 14 | match_input("one"); 15 | match_input(#{ field: 42 }); 16 | -------------------------------------------------------------------------------- /scripts/book/structs/user_database.rn: -------------------------------------------------------------------------------- 1 | struct User { 2 | username, 3 | active, 4 | } 5 | 6 | impl User { 7 | fn set_active(self, active) { 8 | self.active = active; 9 | } 10 | 11 | fn describe(self) { 12 | if self.active { 13 | println!("{} is active.", self.username); 14 | } else { 15 | println!("{} is inactive.", self.username); 16 | } 17 | } 18 | } 19 | 20 | let user = User { username: "setbac", active: false }; 21 | 22 | user.describe(); 23 | user.set_active(true); 24 | user.describe(); 25 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/btree/set_val.rs: -------------------------------------------------------------------------------- 1 | use crate::clone::TryClone; 2 | use crate::error::Error; 3 | 4 | /// Zero-Sized Type (ZST) for internal `BTreeSet` values. 5 | /// Used instead of `()` to differentiate between: 6 | /// * `BTreeMap` (possible user-defined map) 7 | /// * `BTreeMap` (internal set representation) 8 | #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Default)] 9 | pub(crate) struct SetValZST; 10 | 11 | impl TryClone for SetValZST { 12 | fn try_clone(&self) -> Result { 13 | Ok(Self) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /crates/rune/src/modules/u64.rs: -------------------------------------------------------------------------------- 1 | //! Integers. 2 | 3 | use core::cmp::Ordering; 4 | use core::num::ParseIntError; 5 | 6 | use crate as rune; 7 | use crate::alloc::string::TryToString; 8 | use crate::{ContextError, Module}; 9 | 10 | /// Unsigned integers. 11 | /// 12 | /// This provides methods for computing over and parsing 64-bit unsigned integers. 13 | #[rune::module(::std::u64)] 14 | pub fn module() -> Result { 15 | let mut m = Module::from_meta(self::module__meta)?; 16 | unsigned!(m, u64); 17 | Ok(m) 18 | } 19 | 20 | unsigned_fns!(u64); 21 | -------------------------------------------------------------------------------- /crates/rune/src/hir/arena/tests.rs: -------------------------------------------------------------------------------- 1 | use super::Arena; 2 | 3 | #[test] 4 | fn basic() { 5 | let arena = Arena::new(); 6 | 7 | let first = arena.alloc(1u32).unwrap(); 8 | let second = arena.alloc(2u32).unwrap(); 9 | 10 | assert_eq!(first, &1); 11 | assert_eq!(second, &2); 12 | } 13 | 14 | #[test] 15 | fn slices() { 16 | let arena = Arena::new(); 17 | 18 | let hello = arena.alloc_bytes(b"hello").unwrap(); 19 | let world = arena.alloc_bytes(b"world").unwrap(); 20 | 21 | assert_eq!(hello, b"hello"); 22 | assert_eq!(world, b"world"); 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/src/tests/unreachable.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use WarningDiagnosticKind::*; 4 | 5 | #[test] 6 | fn unreachable_iter() { 7 | assert_warnings! { 8 | r#" 9 | pub fn function() { 10 | for _ in { return 10 } { 1 } 11 | 2 12 | } 13 | "#, 14 | span, 15 | Unreachable { cause: span!(50, 63), .. } => { 16 | assert_eq!(span, span!(64, 69)); 17 | }, 18 | Unreachable { cause: span!(41, 69), .. } => { 19 | assert_eq!(span, span!(82, 83)); 20 | }, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/book/structs/struct_matching.rn: -------------------------------------------------------------------------------- 1 | struct User { 2 | username, 3 | active, 4 | } 5 | 6 | impl User { 7 | fn describe(self) { 8 | match self { 9 | User { username: "setbac", .. } => { 10 | println!("Yep, it's setbac."); 11 | } 12 | User { username, .. } => { 13 | println!("Other user: {username}."); 14 | } 15 | } 16 | } 17 | } 18 | 19 | let user = User { username: "setbac", active: false }; 20 | 21 | user.describe(); 22 | user.username = "newt"; 23 | user.describe(); 24 | -------------------------------------------------------------------------------- /crates/rune/tests/lazy_and_or.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn lazy_and_or() { 3 | let result = (|| true || return false)(); 4 | assert_eq!(result, true); 5 | 6 | let result = (|| false && return true)(); 7 | assert_eq!(result, false); 8 | 9 | let result = (|| (false || false || { 10 | return true; 11 | false 12 | } || false))(); 13 | 14 | assert_eq!(result, true); 15 | 16 | let result = (|| { 17 | false && false && { 18 | return false; 19 | false 20 | } || true 21 | })(); 22 | assert_eq!(result, true); 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/src/tests/bug_422.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::mixed_case_hex_literals)] 2 | 3 | prelude!(); 4 | 5 | /// This ensures that `e` literals found in hex number literals are not treated 6 | /// as exponents. 7 | #[test] 8 | pub fn test_bug_422() { 9 | macro_rules! test_case { 10 | ($expr:expr) => { 11 | let value: u32 = rune!($expr); 12 | assert_eq!(value, $expr); 13 | }; 14 | } 15 | 16 | test_case!(0x40c61d + 1); 17 | test_case!(0x40c61f - 1); 18 | test_case!(0x40c61e); 19 | test_case!(0x40c61E); 20 | test_case!(0x40C61e); 21 | } 22 | -------------------------------------------------------------------------------- /scripts/rand.rn: -------------------------------------------------------------------------------- 1 | let rng = rand::SmallRng::try_from_os_rng()?; 2 | let v = rng.random::(); 3 | println!("Random u64: {v}"); 4 | let v = rng.random_range::(-100..100); 5 | println!("Random i64 in range: {v}"); 6 | let v = rng.random::(); 7 | println!("Random char: {v:?}"); 8 | 9 | let rng = rand::StdRng::try_from_os_rng()?; 10 | let v = rng.random::(); 11 | println!("Random u64: {v}"); 12 | let v = rng.random_range::(-100..100); 13 | println!("Random i64 in range: {v}"); 14 | let v = rng.random_range::('a'..'z'); 15 | println!("Random char between 'a' and 'z': {v:?}"); 16 | -------------------------------------------------------------------------------- /crates/rune/src/modules/num.rs: -------------------------------------------------------------------------------- 1 | //! Working with numbers. 2 | 3 | use core::num::{ParseFloatError, ParseIntError}; 4 | 5 | use crate as rune; 6 | use crate::{ContextError, Module}; 7 | 8 | /// Working with numbers. 9 | /// 10 | /// This module provides types generic for working over numbers, such as errors 11 | /// when a number cannot be parsed. 12 | #[rune::module(::std::num)] 13 | pub fn module() -> Result { 14 | let mut module = Module::from_meta(self::module__meta)?; 15 | module.ty::()?; 16 | module.ty::()?; 17 | Ok(module) 18 | } 19 | -------------------------------------------------------------------------------- /crates/rune/src/tests/result.rs: -------------------------------------------------------------------------------- 1 | //! Test for result functions 2 | 3 | prelude!(); 4 | 5 | use VmErrorKind::*; 6 | 7 | #[test] 8 | fn panics() { 9 | assert_vm_error!( 10 | "Err(\"Error\").expect(\"Err('Error')\")", 11 | Panic { reason } => { 12 | assert_eq!(reason.to_string(), "Err('Error'): \"Error\"") 13 | } 14 | ); 15 | 16 | assert_vm_error!( 17 | "Err(\"Error\").unwrap()", 18 | Panic { reason } => { 19 | assert_eq!(reason.to_string(), "Called `Result::unwrap()` on an `Err` value: \"Error\"") 20 | } 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /scripts/book/objects/json.rn: -------------------------------------------------------------------------------- 1 | async fn get_commits(repo, limit) { 2 | let limit = limit.unwrap_or(10); 3 | 4 | let client = http::Client::new(); 5 | let request = client.get(`https://api.github.com/repos/${repo}/commits`); 6 | let response = request.header("User-Agent", "Rune").send().await?; 7 | let text = response.text().await?; 8 | let json = json::from_string(text)?; 9 | 10 | let commits = json.iter().take(limit).map(|e| e.sha).collect::(); 11 | Ok(commits) 12 | } 13 | 14 | for commit in get_commits("rune-rs/rune", Some(5)).await? { 15 | println!("{commit}"); 16 | } 17 | -------------------------------------------------------------------------------- /book/README.md: -------------------------------------------------------------------------------- 1 | # The Rune Programming Language Book 2 | 3 | This is a book built with [mdbook](https://github.com/rust-lang/mdBook). 4 | 5 | You can build the book with: 6 | 7 | ```bash 8 | cargo install mdbook 9 | mdbook build --open 10 | ``` 11 | 12 | ## highlight.js fork 13 | 14 | This book uses a [custom fork] of highlight.js with support for rune. 15 | 16 | [custom fork]: https://github.com/rune-rs/highlight.js/tree/rune 17 | 18 | The fork is built using: 19 | 20 | ```bash 21 | npm install 22 | node tools/build.js -h :common 23 | ``` 24 | 25 | Then you copy `build/highlight.js.min` to `src/highlight.js`. 26 | -------------------------------------------------------------------------------- /crates/rune-macros/src/path_in.rs: -------------------------------------------------------------------------------- 1 | use syn::parse::{Parse, ParseStream}; 2 | use syn::Token; 3 | 4 | pub(super) struct PathIn { 5 | pub(super) in_crate: syn::Path, 6 | #[allow(unused)] 7 | pub(super) comma_token: Token![,], 8 | pub(super) item: T, 9 | } 10 | 11 | impl Parse for PathIn 12 | where 13 | T: Parse, 14 | { 15 | #[inline] 16 | fn parse(input: ParseStream) -> syn::Result { 17 | Ok(Self { 18 | in_crate: input.parse()?, 19 | comma_token: input.parse()?, 20 | item: input.parse()?, 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /editors/code/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": false, // set this to true to hide the "out" folder with the compiled JS files 4 | "dist": false // set this to true to hide the "dist" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true, // set this to false to include "out" folder in search results 8 | "dist": true // set this to false to include "dist" folder in search results 9 | }, 10 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 11 | "typescript.tsc.autoDetect": "off" 12 | } -------------------------------------------------------------------------------- /scripts/book/async/async_http_timeout.rn: -------------------------------------------------------------------------------- 1 | struct Timeout; 2 | 3 | async fn request(timeout) { 4 | let request = http::get(`http://httpstat.us/200?sleep=${timeout}`); 5 | let timeout = time::sleep(time::Duration::from_secs(2)); 6 | 7 | let result = select { 8 | _ = timeout => Err(Timeout), 9 | res = request => res, 10 | }?; 11 | 12 | println!("{}", result.status()); 13 | Ok(()) 14 | } 15 | 16 | if let Err(Timeout) = request(1000).await { 17 | println!("Request timed out!"); 18 | } 19 | 20 | if let Err(Timeout) = request(4000).await { 21 | println!("Request timed out!"); 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune/tests/float.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn test_float_fns() { 3 | let n = 1.0.min(2.0); 4 | assert_eq!(n, 1.0); 5 | 6 | let n = std::f64::min(1.0, 2.0); 7 | assert_eq!(n, 1.0); 8 | 9 | let n = 1.0.max(2.0); 10 | assert_eq!(n, 2.0); 11 | 12 | let n = std::f64::max(1.0, 2.0); 13 | assert_eq!(n, 2.0); 14 | 15 | let n = (-10.0).abs(); 16 | assert_eq!(n, 10.0); 17 | 18 | let n = std::f64::abs(-10.0); 19 | assert_eq!(n, 10.0); 20 | 21 | let n = (12.0).powf(3.0); 22 | assert_eq!(n, 1728.0); 23 | 24 | let n = std::f64::powf(12.0, 3.0); 25 | assert_eq!(n, 1728.0); 26 | } 27 | -------------------------------------------------------------------------------- /editors/code/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "out", 21 | "dist", 22 | "**/*.d.ts" 23 | ] 24 | } -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_vec.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("[1, \"two\"]"); 7 | rt::("[1, 2,]"); 8 | rt::("[1, 2, foo()]"); 9 | } 10 | 11 | /// A literal vector. 12 | /// 13 | /// * `[,*]` 14 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 15 | #[non_exhaustive] 16 | pub struct ExprVec { 17 | /// Attributes associated with vector. 18 | #[rune(iter, meta)] 19 | pub attributes: Vec, 20 | /// Items in the vector. 21 | pub items: ast::Bracketed, 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune-core/src/item.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alloc")] 2 | mod item_buf; 3 | #[cfg(feature = "alloc")] 4 | pub use self::item_buf::ItemBuf; 5 | 6 | mod item; 7 | pub use self::item::Item; 8 | 9 | mod iter; 10 | pub use self::iter::Iter; 11 | 12 | #[cfg(feature = "alloc")] 13 | mod component; 14 | #[cfg(feature = "alloc")] 15 | pub use self::component::Component; 16 | 17 | mod component_ref; 18 | pub use self::component_ref::ComponentRef; 19 | 20 | mod into_component; 21 | pub use self::into_component::IntoComponent; 22 | 23 | mod internal; 24 | 25 | #[cfg(feature = "musli")] 26 | mod musli; 27 | mod serde; 28 | 29 | #[cfg(test)] 30 | mod tests; 31 | -------------------------------------------------------------------------------- /crates/rune/src/tests/rename_type.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[derive(Any)] 4 | #[rune(name = Bar)] 5 | struct Foo {} 6 | 7 | #[derive(Any)] 8 | struct Bar {} 9 | 10 | #[test] 11 | fn test_rename() -> Result<()> { 12 | let mut module = Module::new(); 13 | module.ty::().unwrap(); 14 | let e = module.ty::().unwrap_err(); 15 | 16 | match e { 17 | ContextError::ConflictingType { item, .. } => { 18 | assert_eq!(item, ItemBuf::with_item(["Bar"])?); 19 | } 20 | actual => { 21 | panic!("Expected conflicting type but got: {actual:?}"); 22 | } 23 | } 24 | 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /crates/rune/src/tests/bug_417.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | /// This tests that all items can be successfully queried for when unused (but 6 | /// be ambiguous as is the case with `Foo::Variant`) and that a module with the 7 | /// same name as an item causes a meta conflict. 8 | #[test] 9 | fn ensure_unambigious_items() { 10 | assert_errors! { 11 | r#"enum Foo { Variant } mod Foo { struct Variant; }"#, 12 | span, 13 | _ => { 14 | assert_eq!(span, span!(21, 28)); 15 | }, 16 | AmbiguousItem { .. } => { 17 | assert_eq!(span, span!(11, 18)); 18 | }, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /scripts/book/types/types.rn: -------------------------------------------------------------------------------- 1 | assert!(() is Tuple, "tuples should be tuples"); 2 | assert!((1, 2) is Tuple, "tuples should be tuples"); 3 | assert!(true is bool, "bools should be bools"); 4 | assert!('a' is char, "chars should be chars"); 5 | assert!(b'a' is u64, "bytes should be unsigned integers"); 6 | assert!(42 is i64, "integers should be integers"); 7 | assert!(42.1 is f64, "floats should be floats"); 8 | assert!("hello" is String, "strings should be strings"); 9 | assert!("x" is not char, "strings are not chars"); 10 | assert!(#{"hello": "world"} is Object, "objects should be objects"); 11 | assert!(["hello", "world"] is Vec, "vectors should be vectors"); 12 | -------------------------------------------------------------------------------- /benches/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks for Rune 2 | 3 | Site: https://rune-rs.github.io/rune/dev/bench/ 4 | 5 | You can run a benchmark by: 6 | 7 | ```sh 8 | cargo bench 9 | ``` 10 | 11 | ## Generating flamegraphs 12 | 13 | Install [`cargo-profile`] (since [`flamegraph` can't run benchmarks] easily): 14 | 15 | ```sh 16 | cargo install cargo-profile 17 | ``` 18 | 19 | Run a single benchmark to generate a `flamegraph.svg` file: 20 | 21 | ```sh 22 | cargo profile flamegraph bench --bench 23 | ``` 24 | 25 | [`cargo-profile`]: https://github.com/kdy1/cargo-profile 26 | [`flamegraph` can't run benchmarks]: https://github.com/flamegraph-rs/flamegraph/issues/80 27 | -------------------------------------------------------------------------------- /crates/rune/src/modules/stream.rs: -------------------------------------------------------------------------------- 1 | //! Asynchronous streams. 2 | 3 | use crate as rune; 4 | use crate::runtime::Stream; 5 | use crate::{ContextError, Module}; 6 | 7 | /// Asynchronous streams. 8 | #[rune::module(::std::stream)] 9 | pub fn module() -> Result { 10 | let mut m = Module::from_meta(self::module__meta)?; 11 | m.ty::()?; 12 | m.function_meta(Stream::next_shared__meta)?; 13 | m.function_meta(Stream::resume_shared__meta)?; 14 | m.function_meta(Stream::debug__meta)?; 15 | m.function_meta(Stream::clone__meta)?; 16 | m.implement_trait::(rune::item!(::std::clone::Clone))?; 17 | Ok(m) 18 | } 19 | -------------------------------------------------------------------------------- /crates/rune/src/tests/capture.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_closure() { 5 | let number: i64 = rune! { 6 | let a = 1; 7 | let b = 2; 8 | let closure = { let c = 4; |d, e| |f| a + b + c + d + e + f }; 9 | closure(8, 16)(32) 10 | }; 11 | 12 | assert_eq!(number, 1 + 2 + 4 + 8 + 16 + 32); 13 | } 14 | 15 | #[test] 16 | fn test_async() { 17 | let number: i64 = rune! { 18 | let a = 1; 19 | let b = 2; 20 | let closure = async { let c = 4; |d, e| |f| a + b + c + d + e + f }; 21 | closure.await(8, 16)(32) 22 | }; 23 | 24 | assert_eq!(number, 1 + 2 + 4 + 8 + 16 + 32); 25 | } 26 | -------------------------------------------------------------------------------- /scripts/book/async/async_http_concurrent.rn: -------------------------------------------------------------------------------- 1 | use std::future; 2 | 3 | struct Timeout; 4 | 5 | async fn request(timeout) { 6 | let request = http::get(`http://httpstat.us/200?sleep=${timeout}`); 7 | let timeout = time::sleep(time::Duration::from_secs(2)); 8 | 9 | let result = select { 10 | _ = timeout => Err(Timeout), 11 | res = request => res, 12 | }?; 13 | 14 | Ok(result) 15 | } 16 | 17 | for result in future::join([request(1000), request(4000)]).await { 18 | match result { 19 | Ok(result) => println!("Result: {}", result.status()), 20 | Err(Timeout) => println!("Request timed out!"), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune/src/tests/static_typing.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn deny_static_typing_function() { 7 | assert_errors! { 8 | "fn foo() -> Bar {}", 9 | span!(0, 18), Custom { error } => { 10 | assert_eq!(error.to_string(), "Adding a return type in functions is not supported"); 11 | } 12 | } 13 | } 14 | 15 | #[test] 16 | fn deny_static_typing_field() { 17 | assert_errors! { 18 | "struct Struct { foo: Bar }", 19 | span!(16, 24), Custom { error } => { 20 | assert_eq!(error.to_string(), "Static typing on fields is not supported"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/src/ast/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::ast; 2 | 3 | /// Test if the given expression qualifieis as a block end or not, as with a 4 | /// body in a match expression. 5 | /// 6 | /// This determines if a comma is necessary or not after the expression. 7 | pub(crate) fn is_block_end(expr: &ast::Expr, comma: Option<&T![,]>) -> bool { 8 | match (expr, comma) { 9 | (ast::Expr::Block(..), _) => false, 10 | (ast::Expr::For(..), _) => false, 11 | (ast::Expr::While(..), _) => false, 12 | (ast::Expr::If(..), _) => false, 13 | (ast::Expr::Match(..), _) => false, 14 | (_, Some(..)) => false, 15 | (_, None) => true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/rune/src/module/install_with.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::Ordering; 2 | 3 | use crate::{ContextError, Hash}; 4 | 5 | use super::Module; 6 | 7 | /// Trait to handle the installation of auxilliary functions for a type 8 | /// installed into a module. 9 | pub trait InstallWith { 10 | /// Hook to install more things into the module. 11 | fn install_with(_: &mut Module) -> Result<(), ContextError> { 12 | Ok(()) 13 | } 14 | } 15 | 16 | impl InstallWith for i64 {} 17 | impl InstallWith for u64 {} 18 | impl InstallWith for f64 {} 19 | impl InstallWith for char {} 20 | impl InstallWith for bool {} 21 | impl InstallWith for Ordering {} 22 | impl InstallWith for Hash {} 23 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/protocol.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc; 2 | #[cfg(feature = "doc")] 3 | use crate::alloc::Vec; 4 | use crate::compile::meta; 5 | use crate::function_meta::{AssociatedName, ToInstance}; 6 | use crate::Hash; 7 | 8 | #[doc(inline)] 9 | pub use rune_core::protocol::Protocol; 10 | 11 | impl ToInstance for &'static Protocol { 12 | #[inline] 13 | fn to_instance(self) -> alloc::Result { 14 | Ok(AssociatedName { 15 | kind: meta::AssociatedKind::Protocol(self), 16 | function_parameters: Hash::EMPTY, 17 | #[cfg(feature = "doc")] 18 | parameter_types: Vec::new(), 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/vec_deque/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! __impl_slice_eq1 { 2 | ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => { 3 | impl PartialEq<$rhs> for $lhs 4 | where 5 | T: PartialEq, 6 | $($constraints)* 7 | { 8 | fn eq(&self, other: &$rhs) -> bool { 9 | if self.len() != other.len() { 10 | return false; 11 | } 12 | let (sa, sb) = self.as_slices(); 13 | let (oa, ob) = other[..].split_at(sa.len()); 14 | sa == oa && sb == ob 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/http.rn: -------------------------------------------------------------------------------- 1 | let response = http::get("http://worldtimeapi.org/api/ip").await?; 2 | let json = response.json().await?; 3 | 4 | let timezone = json["timezone"]; 5 | 6 | if timezone != () { 7 | dbg!(timezone); 8 | } 9 | 10 | let body = json::to_bytes(#{ "hello": "world" })?; 11 | 12 | let client = http::Client::new(); 13 | let response = client.post("https://postman-echo.com/post").body_bytes(body).send().await?; 14 | 15 | let response = response.json().await?; 16 | 17 | let content_length = std::i64::parse(response["headers"]["content-length"])?; 18 | 19 | if content_length is i64 { 20 | dbg!("it is indeed an integer"); 21 | } 22 | 23 | dbg!(content_length + 20, response); 24 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_try.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("42?"); 7 | rt::("foo()?"); 8 | } 9 | 10 | /// A try expression. 11 | /// 12 | /// * `?`. 13 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 14 | #[non_exhaustive] 15 | pub struct ExprTry { 16 | /// Attributes associated with expression. 17 | #[rune(iter)] 18 | pub attributes: Vec, 19 | /// The expression being awaited. 20 | pub expr: Box, 21 | /// The try operator `?`. 22 | pub try_token: T![?], 23 | } 24 | 25 | expr_parse!(Try, ExprTry, "try expression"); 26 | -------------------------------------------------------------------------------- /crates/rune/src/parse/resolve.rs: -------------------------------------------------------------------------------- 1 | use crate::compile; 2 | use crate::macros::Storage; 3 | use crate::Sources; 4 | 5 | /// A resolve context. 6 | #[derive(Clone, Copy)] 7 | pub struct ResolveContext<'a> { 8 | /// Sources to use. 9 | pub(crate) sources: &'a Sources, 10 | /// Storage to use in resolve context. 11 | pub(crate) storage: &'a Storage, 12 | } 13 | 14 | /// A type that can be resolved to an internal value based on a source. 15 | pub trait Resolve<'a> { 16 | /// The output type being resolved into. 17 | type Output: 'a; 18 | 19 | /// Resolve the value from parsed AST. 20 | fn resolve(&self, cx: ResolveContext<'a>) -> compile::Result; 21 | } 22 | -------------------------------------------------------------------------------- /crates/rune/src/compile/names/tests.rs: -------------------------------------------------------------------------------- 1 | use super::Names; 2 | use crate::support::Result; 3 | 4 | #[test] 5 | fn insert() -> Result<()> { 6 | let mut names = Names::default(); 7 | assert!(!names.contains(["test"])?); 8 | assert!(!names.insert(["test"]).unwrap()); 9 | assert!(names.contains(["test"])?); 10 | assert!(names.insert(["test"]).unwrap()); 11 | Ok(()) 12 | } 13 | 14 | #[test] 15 | fn contains() -> Result<()> { 16 | let mut names = Names::default(); 17 | assert!(!names.contains(["test"])?); 18 | assert!(!names.insert(["test"]).unwrap()); 19 | assert!(names.contains(["test"])?); 20 | assert!(names.insert(["test"]).unwrap()); 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /crates/rune/tests/instance.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn instance_basic_self() { 3 | struct Foo { 4 | value, 5 | } 6 | 7 | impl Foo { 8 | fn inc(self) { 9 | self.value += 1; 10 | } 11 | } 12 | 13 | let foo = Foo { value: 42 }; 14 | assert_eq!(foo.value, 42); 15 | foo.inc(); 16 | assert_eq!(foo.value, 43); 17 | } 18 | 19 | #[test] 20 | fn instance_chaining() { 21 | struct Foo { 22 | value, 23 | } 24 | 25 | impl Foo { 26 | fn inc(self) { 27 | self.value += 1; 28 | self 29 | } 30 | } 31 | 32 | let foo = Foo { value: 42 }; 33 | assert_eq!(foo.inc().inc().inc().value, 45); 34 | } 35 | -------------------------------------------------------------------------------- /crates/rune/src/parse/peek.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc::Box; 2 | use crate::parse::{Parse, Peeker}; 3 | 4 | /// Implemented by tokens that can be peeked for. 5 | pub trait Peek { 6 | /// Peek the parser for the given token. 7 | fn peek(p: &mut Peeker<'_>) -> bool; 8 | } 9 | 10 | /// Peek implementation for something that is boxed. 11 | impl Peek for Box 12 | where 13 | T: Peek, 14 | { 15 | #[inline] 16 | fn peek(p: &mut Peeker<'_>) -> bool { 17 | T::peek(p) 18 | } 19 | } 20 | 21 | impl Peek for (A, B) 22 | where 23 | A: Parse + Peek, 24 | B: Parse, 25 | { 26 | #[inline] 27 | fn peek(p: &mut Peeker<'_>) -> bool { 28 | A::peek(p) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/doc.rn: -------------------------------------------------------------------------------- 1 | /// Foo documentation. 2 | struct Foo { 3 | /// Struct field. 4 | /// Field A. 5 | a, 6 | /// Struct field. 7 | /// Field B. 8 | b, 9 | } 10 | 11 | /// Test 12 | mod module { 13 | //! Interior comment 1. 14 | //! Interior comment 2. 15 | 16 | /// Bar documentation. 17 | struct Bar {} 18 | } 19 | 20 | mod foo { 21 | enum Foo { 22 | /// This is another test. 23 | Hello, 24 | /// This is a test. 25 | World { 26 | /// Variant struct field. 27 | /// Field A. 28 | a, 29 | /// Variant struct field. 30 | /// Field B. 31 | b, 32 | }, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /editors/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2020" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules" 19 | ], 20 | "include": [ 21 | "src", 22 | "tests" 23 | ] 24 | } -------------------------------------------------------------------------------- /site/sass/_vars.scss: -------------------------------------------------------------------------------- 1 | // used for disabling select, which can get annoying on mobile devices. 2 | // Currently this is only used for disabling selections on the hamburger menu icon (since our menu is CSS-only). 3 | @mixin disable-select { 4 | -webkit-touch-callout: none; 5 | -webkit-user-select: none; 6 | -khtml-user-select: none; 7 | -moz-user-select: none; 8 | -ms-user-select: none; 9 | user-select: none; 10 | } 11 | 12 | $accent: hsl(0, 0%, 21%); 13 | $accent2: #f0f0f0; 14 | $code-color: #e8e8e8; 15 | $outline: rgba(0, 0, 0, .2); 16 | $background: #fff; 17 | $text: #4D4D4D; 18 | $title: #000; 19 | 20 | $error-color: #81011e; 21 | $warning-color: rgb(255, 193, 7); 22 | 23 | $article-width: 800px; 24 | -------------------------------------------------------------------------------- /crates/rune/src/compile/v1/display_named.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | /// Used to ergonomically display an address. 4 | pub(super) struct DisplayNamed { 5 | value: T, 6 | name: Option<&'static str>, 7 | } 8 | 9 | impl DisplayNamed { 10 | #[inline] 11 | pub(super) const fn new(value: T, name: Option<&'static str>) -> Self { 12 | Self { value, name } 13 | } 14 | } 15 | 16 | impl fmt::Display for DisplayNamed 17 | where 18 | T: fmt::Display, 19 | { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | match self.name { 22 | Some(name) => write!(f, "{} ({})", self.value, name), 23 | None => self.value.fmt(f), 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/rune/tests/types.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn types() { 3 | assert!(() is Tuple, "tuples should be tuples"); 4 | assert!((1, 2) is Tuple, "tuples should be tuples"); 5 | assert!(true is bool, "bools should be bools"); 6 | assert!('a' is char, "chars should be chars"); 7 | assert!(b'a' is u64, "a byte should be an unsigned integer"); 8 | assert!(42 is i64, "integers should be integers"); 9 | assert!(42.1 is f64, "floats should be floats"); 10 | assert!("hello" is String, "strings should be strings"); 11 | assert!("x" is not char, "strings are not chars"); 12 | assert!(#{"hello": "world"} is Object, "objects should be objects"); 13 | assert!(["hello", "world"] is Vec, "vectors should be vectors"); 14 | } 15 | -------------------------------------------------------------------------------- /crates/rune/src/ast/prelude.rs: -------------------------------------------------------------------------------- 1 | //! Prelude for ast elements. 2 | 3 | pub(crate) use crate as rune; 4 | pub(crate) use crate::alloc; 5 | pub(crate) use crate::alloc::prelude::*; 6 | pub(crate) use crate::ast; 7 | pub(crate) use crate::ast::{OptionSpanned, Span, Spanned, ToAst}; 8 | pub(crate) use crate::compile::{self, ErrorKind, ItemId}; 9 | pub(crate) use crate::macros::{MacroContext, SyntheticKind, ToTokens, TokenStream}; 10 | pub(crate) use crate::parse::{ 11 | Expectation, IntoExpectation, NonZeroId, Parse, Parser, Peek, Peeker, Resolve, ResolveContext, 12 | }; 13 | 14 | pub(crate) type Result = core::result::Result; 15 | 16 | #[cfg(all(test, not(miri)))] 17 | pub(crate) use crate::ast::testing::{rt, rt_with}; 18 | -------------------------------------------------------------------------------- /crates/rune/tests/non_ascii_idents.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn non_ascii_identifiers() { 3 | // Creating a variable. 4 | let 另一個世界 = "三體世界"; 5 | 6 | // Reference to the variable. 7 | let 世界 = 另一個世界; 8 | 9 | // In template interpolation. 10 | let 高論 = `你好,${世界}。`; 11 | assert_eq!(高論, "你好,三體世界。"); 12 | 13 | // In string formatting. 14 | println!("我對{另一個世界}說話"); 15 | } 16 | 17 | #[test] 18 | fn non_ascii_function_name_and_arguments() { 19 | fn 口號(蟲子, 主) { 20 | `消滅${蟲子}暴政,世界屬於${主}!` 21 | } 22 | assert_eq!("消滅人類暴政,世界屬於三體!", 口號("人類", "三體")); 23 | } 24 | 25 | #[test] 26 | fn alphanumeric_and_underscore() { 27 | let aB_1 = (); 28 | let Ab_2 = (); 29 | let _ = (); 30 | let __甲_乙_丙_丁__ = (); 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/tests/option.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn option_some_some() { 3 | let out = match Some("some") { 4 | Some("some") => 1, 5 | _ => 2, 6 | }; 7 | 8 | assert_eq!(out, 1); 9 | } 10 | 11 | #[test] 12 | fn option_some_other() { 13 | let out = match Some("some") { 14 | Some("other") => 1, 15 | _ => 2, 16 | }; 17 | 18 | assert_eq!(out, 2); 19 | } 20 | 21 | #[test] 22 | fn option_none() { 23 | let out = match None { 24 | None => 1, 25 | _ => 2, 26 | }; 27 | 28 | assert_eq!(out, 1); 29 | } 30 | 31 | #[test] 32 | fn option_none_some() { 33 | let out = match None { 34 | Some("some") => 1, 35 | _ => 2, 36 | }; 37 | 38 | assert_eq!(out, 2); 39 | } 40 | -------------------------------------------------------------------------------- /scripts/generator_resume.rn: -------------------------------------------------------------------------------- 1 | use std::ops::generator::GeneratorState; 2 | 3 | fn foo() { 4 | let a = yield 1; 5 | let b = yield a; 6 | b 7 | } 8 | 9 | let gen = foo(); 10 | let result = 0; 11 | 12 | // First argument to resume is ignored since it's just used to start the 13 | // generator. 14 | if let GeneratorState::Yielded(value) = gen.resume(()) { 15 | result += value; 16 | } else { 17 | panic!("unexpected"); 18 | } 19 | 20 | if let GeneratorState::Yielded(value) = gen.resume(2) { 21 | result += value; 22 | } else { 23 | panic!("unexpected"); 24 | } 25 | 26 | if let GeneratorState::Complete(value) = gen.resume(3) { 27 | result += value; 28 | } else { 29 | panic!("unexpected"); 30 | } 31 | 32 | println!("{result}"); 33 | -------------------------------------------------------------------------------- /crates/rune/src/ace/static/rune-completer.js: -------------------------------------------------------------------------------- 1 | ace.define('ace/autocomplete/rune', 2 | ["require", "exports", "module"], 3 | function (require, exports, module) { 4 | exports.Completer = { 5 | getCompletions: (editor, session, pos, prefix, callback) => { 6 | if (prefix.length === 0) { 7 | callback(null, []); 8 | return; 9 | } 10 | 11 | var token = session.getTokenAt(pos.row, pos.column - 1).value; 12 | 13 | if (token.includes(".")) { 14 | callback(null, instance); 15 | } else { 16 | callback(null, fixed); 17 | } 18 | }, 19 | }; 20 | } 21 | ); 22 | -------------------------------------------------------------------------------- /crates/rune/tests/variants.rn: -------------------------------------------------------------------------------- 1 | /// Tests that different variants of the same enum can be compared to each other 2 | /// See: https://github.com/rune-rs/rune/pull/215 3 | #[test] 4 | fn assert_variant_comparisons() { 5 | enum Units { 6 | A, 7 | B, 8 | } 9 | 10 | assert_ne!(Units::A, Units::B); 11 | assert_eq!(Units::A, Units::A); 12 | 13 | enum Mixed1 { 14 | A(a), 15 | B, 16 | } 17 | 18 | assert_ne!(Mixed1::A(10), Mixed1::B); 19 | assert_eq!(Mixed1::A(10), Mixed1::A(10)); 20 | 21 | enum Mixed2 { 22 | A { 23 | a, 24 | }, 25 | B, 26 | } 27 | 28 | assert_ne!(Mixed2::A { a: 10 }, Mixed2::B); 29 | assert_eq!(Mixed2::A { a: 10 }, Mixed2::A { a: 10 }); 30 | } 31 | -------------------------------------------------------------------------------- /crates/rune-modules/src/rand/error.rs: -------------------------------------------------------------------------------- 1 | use rune::alloc; 2 | use rune::alloc::fmt::TryWrite; 3 | use rune::runtime::Formatter; 4 | use rune::Any; 5 | 6 | /// An error returned by methods in the `rand` module. 7 | #[derive(Debug, Any)] 8 | #[rune(item = ::rand)] 9 | pub(super) struct Error { 10 | pub(super) inner: getrandom::Error, 11 | } 12 | 13 | impl From for Error { 14 | #[inline] 15 | fn from(inner: getrandom::Error) -> Self { 16 | Self { inner } 17 | } 18 | } 19 | 20 | impl Error { 21 | /// Write a display representation the error. 22 | #[rune::function(instance, protocol = DISPLAY_FMT)] 23 | fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { 24 | write!(f, "{}", self.inner) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /editors/code/src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /crates/rune/src/ast/fn_arg.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("self"); 7 | rt::("_"); 8 | rt::("abc"); 9 | } 10 | 11 | /// A single argument in a closure. 12 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 13 | #[non_exhaustive] 14 | pub enum FnArg { 15 | /// The `self` parameter. 16 | SelfValue(T![self]), 17 | /// Function argument is a pattern binding. 18 | Pat(ast::Pat), 19 | } 20 | 21 | impl Parse for FnArg { 22 | fn parse(p: &mut Parser<'_>) -> Result { 23 | Ok(match p.nth(0)? { 24 | K![self] => Self::SelfValue(p.parse()?), 25 | _ => Self::Pat(p.parse()?), 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/rune/src/tests/comments.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_non_terminated_multiline_comments() { 7 | assert_errors! { 8 | r#"/* foo"#, 9 | span, ExpectedMultilineCommentTerm => { 10 | assert_eq!(span, span!(0, 6)); 11 | } 12 | }; 13 | 14 | assert_errors! { 15 | r#"/* 16 | foo 17 | bar"#, 18 | span, ExpectedMultilineCommentTerm => { 19 | assert_eq!(span, span!(0, 26)); 20 | } 21 | }; 22 | 23 | assert_errors! { 24 | r#" 25 | foo 26 | /* 27 | foo 28 | bar"#, 29 | span, ExpectedMultilineCommentTerm => { 30 | assert_eq!(span, span!(21, 47)); 31 | } 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_empty.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | /// A prioritized expression group without delimiters ``. 4 | /// 5 | /// These groups are only produced during internal desugaring. Most notably 6 | /// through the use of template literals. 7 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 8 | #[non_exhaustive] 9 | pub struct ExprEmpty { 10 | /// Attributes associated with expression. 11 | #[rune(iter)] 12 | pub attributes: Vec, 13 | /// The open parenthesis. 14 | pub open: ast::OpenEmpty, 15 | /// The grouped expression. 16 | pub expr: Box, 17 | /// The close parenthesis. 18 | pub close: ast::CloseEmpty, 19 | } 20 | 21 | expr_parse!(Empty, ExprEmpty, "empty group expression"); 22 | -------------------------------------------------------------------------------- /crates/rune/src/doc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Helper to generate documentation from a context. 2 | 3 | #[cfg(feature = "cli")] 4 | mod context; 5 | #[cfg(feature = "cli")] 6 | pub(crate) use self::context::{Context, Function, Kind, Meta, Signature}; 7 | 8 | #[cfg(feature = "cli")] 9 | mod artifacts; 10 | #[cfg(feature = "cli")] 11 | pub(crate) use self::artifacts::{Artifacts, TestKind, TestParams}; 12 | 13 | #[cfg(feature = "cli")] 14 | mod templating; 15 | 16 | #[cfg(feature = "cli")] 17 | mod build; 18 | #[cfg(feature = "cli")] 19 | pub(crate) use self::build::build; 20 | 21 | #[cfg(feature = "languageserver")] 22 | mod visitor; 23 | #[cfg(feature = "languageserver")] 24 | pub(crate) use self::visitor::{Visitor, VisitorData}; 25 | 26 | #[cfg(feature = "cli")] 27 | pub(crate) mod markdown; 28 | -------------------------------------------------------------------------------- /crates/rune-cli/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Context as _}; 2 | use std::env; 3 | use std::fs; 4 | use std::path::PathBuf; 5 | use std::process::Command; 6 | 7 | fn main() -> anyhow::Result<()> { 8 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").ok_or_else(|| anyhow!("missing OUT_DIR"))?); 9 | 10 | let version = if let Ok(rune_version) = env::var("RUNE_VERSION") { 11 | rune_version 12 | } else { 13 | let output = Command::new("git") 14 | .args(["rev-parse", "--short", "HEAD"]) 15 | .output()?; 16 | 17 | let rev = std::str::from_utf8(&output.stdout)?.trim(); 18 | format!("git-{rev}") 19 | }; 20 | 21 | fs::write(out_dir.join("version.txt"), version).context("writing version.txt")?; 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_assign.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("a = 2"); 7 | rt::("a = b = 3"); 8 | } 9 | 10 | /// An assign expression. 11 | /// 12 | /// * `a = b`. 13 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 14 | #[non_exhaustive] 15 | pub struct ExprAssign { 16 | /// Attributes associated with the assign expression. 17 | #[rune(iter)] 18 | pub attributes: Vec, 19 | /// The expression being assigned to. 20 | pub lhs: Box, 21 | /// The equals sign `=`. 22 | pub eq: T![=], 23 | /// The value. 24 | pub rhs: Box, 25 | } 26 | 27 | expr_parse!(Assign, ExprAssign, "assign expression"); 28 | -------------------------------------------------------------------------------- /crates/rune/src/tests/binary.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_binary_exprs() { 7 | assert_errors! { 8 | r#"0 < 10 >= 10"#, 9 | span!(0, 6), PrecedenceGroupRequired => { 10 | } 11 | }; 12 | 13 | // Test solving precedence with groups. 14 | assert_parse!(r#"(0 < 10) >= 10"#); 15 | assert_parse!(r#"0 < (10 >= 10)"#); 16 | assert_parse!(r#"0 < 10 && 10 > 0"#); 17 | assert_parse!(r#"0 < 10 && 10 > 0 || true"#); 18 | assert_parse!(r#"false || return"#); 19 | } 20 | 21 | #[test] 22 | fn test_basic_operator_precedence() { 23 | let result: bool = rune!(10 < 5 + 10 && 5 > 4); 24 | assert!(result); 25 | 26 | let result: bool = rune!(10 < 5 - 10 && 5 > 4); 27 | assert!(!result); 28 | } 29 | -------------------------------------------------------------------------------- /crates/rune/src/ace/mod.rs: -------------------------------------------------------------------------------- 1 | mod autocomplete; 2 | pub(crate) use self::autocomplete::build as build_autocomplete; 3 | 4 | use anyhow::{anyhow, Context as _, Result}; 5 | 6 | use crate::alloc::borrow::Cow; 7 | use crate::doc::Artifacts; 8 | 9 | mod embed { 10 | use rust_embed::RustEmbed; 11 | 12 | #[derive(RustEmbed)] 13 | #[folder = "src/ace/static"] 14 | pub(super) struct Assets; 15 | } 16 | 17 | pub(crate) fn theme(artifacts: &mut Artifacts) -> Result<()> { 18 | for name in ["rune-mode.js", "rune-highlight-rules.js"] { 19 | artifacts.asset(false, name, || { 20 | let file = embed::Assets::get(name).with_context(|| anyhow!("missing {name}"))?; 21 | Ok(Cow::try_from(file.data)?) 22 | })?; 23 | } 24 | 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /crates/rune/src/ast/tests.rs: -------------------------------------------------------------------------------- 1 | use std::string::String; 2 | 3 | use super::unescape::{parse_hex_escape, parse_unicode_escape}; 4 | 5 | macro_rules! input { 6 | ($string:expr) => { 7 | &mut String::from($string).char_indices().peekable() 8 | }; 9 | } 10 | 11 | #[test] 12 | fn test_parse_hex_escape() { 13 | assert!(parse_hex_escape(input!("a")).is_err()); 14 | 15 | let c = parse_hex_escape(input!("7f")).unwrap(); 16 | assert_eq!(c, 0x7f); 17 | } 18 | 19 | #[test] 20 | fn test_parse_unicode_escape() { 21 | parse_unicode_escape(input!("{0}")).unwrap(); 22 | 23 | let c = parse_unicode_escape(input!("{1F4AF}")).unwrap(); 24 | assert_eq!(c, '💯'); 25 | 26 | let c = parse_unicode_escape(input!("{1f4af}")).unwrap(); 27 | assert_eq!(c, '💯'); 28 | } 29 | -------------------------------------------------------------------------------- /crates/rune/tests/bug_838.rn: -------------------------------------------------------------------------------- 1 | // This ensures that unary operations do not clobber a slot. 2 | // https://github.com/rune-rs/rune/issues/838 3 | 4 | #[test] 5 | fn negation_simple() { 6 | let b = -1; 7 | let d = 0 + -b; 8 | assert_eq!(d, 1); 9 | assert_eq!(b, -1); 10 | } 11 | 12 | #[test] 13 | fn negation_simple_chain() { 14 | let b = -1; 15 | let d = 0 + -b; 16 | d = 0 + -b; 17 | d = 0 + -b; 18 | d = 0 + -b; 19 | assert_eq!(d, 1); 20 | assert_eq!(b, -1); 21 | } 22 | 23 | #[test] 24 | fn negation() { 25 | let a = 1; 26 | let b = -2; 27 | let c = -b; 28 | let d = 1 < -b; 29 | let e = 1 < -b; 30 | 31 | assert!(d); 32 | assert!(e); 33 | assert_eq!(a, 1); 34 | assert_eq!(b, -2); 35 | assert_eq!(c, 2); 36 | } 37 | -------------------------------------------------------------------------------- /crates/rune/tests/result.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn result_map() { 3 | let out = Ok(1).map(|v| v + 1); 4 | assert_eq!(out, Ok(2)); 5 | } 6 | 7 | #[test] 8 | fn result_and_then() { 9 | let out = Ok(1).and_then(|v| Ok(v + 1)); 10 | assert_eq!(out, Ok(2)); 11 | } 12 | 13 | #[test] 14 | fn result_and_then_error() { 15 | let out = Ok(1).and_then(|v| Err("Failed")); 16 | assert_eq!(out, Err("Failed")); 17 | } 18 | 19 | #[test] 20 | fn result_expect_some() { 21 | let out = Ok(1).expect("Ok"); 22 | assert_eq!(out, 1); 23 | } 24 | 25 | #[test] 26 | fn result_unwrap_some() { 27 | let out = Ok(1).unwrap(); 28 | assert_eq!(out, 1); 29 | } 30 | 31 | #[test] 32 | fn result_unwrap_or() { 33 | let out = Err("Error").unwrap_or(10); 34 | assert_eq!(out, 10); 35 | } 36 | -------------------------------------------------------------------------------- /crates/rune-languageserver/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Context as _}; 2 | use std::env; 3 | use std::fs; 4 | use std::path::PathBuf; 5 | use std::process::Command; 6 | 7 | fn main() -> anyhow::Result<()> { 8 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").ok_or_else(|| anyhow!("missing OUT_DIR"))?); 9 | 10 | let version = if let Ok(rune_version) = env::var("RUNE_VERSION") { 11 | rune_version 12 | } else { 13 | let output = Command::new("git") 14 | .args(["rev-parse", "--short", "HEAD"]) 15 | .output()?; 16 | 17 | let rev = std::str::from_utf8(&output.stdout)?.trim(); 18 | format!("git-{rev}") 19 | }; 20 | 21 | fs::write(out_dir.join("version.txt"), version).context("writing version.txt")?; 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_lit.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("42"); 7 | rt::("\"test\""); 8 | rt::("#[attr] 42"); 9 | } 10 | 11 | /// A literal expression. With the addition of being able to receive attributes, 12 | /// this is identical to [ast::Lit]. 13 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 14 | #[rune(parse = "meta_only")] 15 | #[non_exhaustive] 16 | pub struct ExprLit { 17 | /// Attributes associated with the literal expression. 18 | #[rune(iter, meta)] 19 | pub attributes: Vec, 20 | /// The literal in the expression. 21 | pub lit: ast::Lit, 22 | } 23 | 24 | expr_parse!(Lit, ExprLit, "literal expression"); 25 | -------------------------------------------------------------------------------- /crates/rune/src/location.rs: -------------------------------------------------------------------------------- 1 | use crate::{SourceId, Span}; 2 | use std::fmt; 3 | 4 | /// A source location. 5 | #[derive(Default, Clone, Copy)] 6 | #[non_exhaustive] 7 | pub struct Location { 8 | /// The source id of the file of the location. 9 | pub source_id: SourceId, 10 | /// The span of the location. 11 | pub span: Span, 12 | } 13 | 14 | impl Location { 15 | /// Construct a new location. 16 | pub fn new(source_id: SourceId, span: Span) -> Self { 17 | Self { source_id, span } 18 | } 19 | } 20 | 21 | impl fmt::Debug for Location { 22 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 23 | f.debug_tuple("Location") 24 | .field(&self.source_id) 25 | .field(&self.span) 26 | .finish() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/rune/src/workspace/glob/tests.rs: -------------------------------------------------------------------------------- 1 | use super::Fragment; 2 | use crate::support::Result; 3 | 4 | #[test] 5 | fn test_fragment() -> Result<()> { 6 | let fragment = Fragment::parse("abc*def.*")?; 7 | assert!(fragment.is_match("abc_xyz_def.exe")?); 8 | assert!(fragment.is_match("abc_xyz_def.")?); 9 | assert!(!fragment.is_match("ab_xyz_def.exe")?); 10 | assert!(!fragment.is_match("abcdef")?); 11 | assert!(!fragment.is_match("abc_xyz_def")?); 12 | 13 | let fragment = Fragment::parse("*def")?; 14 | assert!(fragment.is_match("abcdef")?); 15 | assert!(!fragment.is_match("abcdeftrailing")?); 16 | 17 | let fragment = Fragment::parse("abc*")?; 18 | assert!(fragment.is_match("abcdef")?); 19 | assert!(!fragment.is_match("leadingabc")?); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /crates/rune-modules/src/rand/os_error.rs: -------------------------------------------------------------------------------- 1 | use rune::alloc; 2 | use rune::alloc::fmt::TryWrite; 3 | use rune::runtime::Formatter; 4 | use rune::Any; 5 | 6 | /// An os error returned by methods in the `rand` module. 7 | #[derive(Debug, Any)] 8 | #[rune(item = ::rand)] 9 | pub(super) struct OsError { 10 | pub(super) inner: rand::rand_core::OsError, 11 | } 12 | 13 | impl From for OsError { 14 | #[inline] 15 | fn from(inner: rand::rand_core::OsError) -> Self { 16 | Self { inner } 17 | } 18 | } 19 | 20 | impl OsError { 21 | /// Write a display representation the error. 22 | #[rune::function(instance, protocol = DISPLAY_FMT)] 23 | fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { 24 | write!(f, "{}", self.inner) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_group.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("(for i in x {})"); 7 | rt::("(1 + 2)"); 8 | } 9 | 10 | /// A prioritized expression group. 11 | /// 12 | /// * `()`. 13 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 14 | #[non_exhaustive] 15 | pub struct ExprGroup { 16 | /// Attributes associated with expression. 17 | #[rune(iter)] 18 | pub attributes: Vec, 19 | /// The open parenthesis. 20 | pub open: ast::OpenParen, 21 | /// The grouped expression. 22 | pub expr: Box, 23 | /// The close parenthesis. 24 | pub close: ast::CloseParen, 25 | } 26 | 27 | expr_parse!(Group, ExprGroup, "group expression"); 28 | -------------------------------------------------------------------------------- /crates/rune/tests/try.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn try_result_err() { 3 | fn foo(a, b) { 4 | Ok(b / a) 5 | } 6 | 7 | fn bar(a, b) { 8 | Err(b / a) 9 | } 10 | 11 | fn inner() { 12 | Ok(foo(2, 4)? + bar(3, 9)?) 13 | } 14 | 15 | assert_eq!(inner(), Err(3)); 16 | } 17 | 18 | #[test] 19 | fn try_option_none() { 20 | struct Bar { 21 | x, 22 | y, 23 | } 24 | 25 | fn inner() { 26 | (Bar { x: Some(1), y: None? }).x 27 | } 28 | 29 | assert_eq!(inner(), None); 30 | } 31 | 32 | #[test] 33 | fn try_ok_err() { 34 | fn foo(a, b) { 35 | Ok(b / a) 36 | } 37 | 38 | fn inner() { 39 | Ok(foo(2, 4)? + { 40 | Err(6 / 2) 41 | }?) 42 | } 43 | 44 | assert_eq!(inner(), Err(3)); 45 | } 46 | -------------------------------------------------------------------------------- /crates/rune/src/shared/gen.rs: -------------------------------------------------------------------------------- 1 | use core::cell::Cell; 2 | use core::num::NonZeroU32; 3 | 4 | use crate::parse::NonZeroId; 5 | 6 | #[derive(Debug)] 7 | pub(crate) struct Gen { 8 | id: Cell, 9 | } 10 | 11 | impl Gen { 12 | /// Construct a new shared generator. 13 | pub(crate) fn new() -> Self { 14 | Self { id: Cell::new(0) } 15 | } 16 | 17 | /// Get the next id. 18 | pub(crate) fn next(&self) -> NonZeroId { 19 | let cur = self.id.get(); 20 | let id = cur 21 | .checked_add(1) 22 | .and_then(NonZeroU32::new) 23 | .expect("ran out of ids"); 24 | self.id.set(id.get()); 25 | NonZeroId::from(id) 26 | } 27 | } 28 | 29 | impl Default for Gen { 30 | fn default() -> Self { 31 | Self::new() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /editors/code/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": [ "/*", "*/" ] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | ["{", "}"], 13 | ["[", "]"], 14 | ["(", ")"], 15 | { "open": "\"", "close": "\"", "notIn": ["string"] } 16 | ], 17 | "surroundingPairs": [ 18 | ["{", "}"], 19 | ["[", "]"], 20 | ["(", ")"], 21 | ["\"", "\""], 22 | ["<", ">"] 23 | ], 24 | "indentationRules": { 25 | "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$", 26 | "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]" 27 | }, 28 | "folding": { 29 | "markers": { 30 | "start": "^\\s*//\\s*#?region\\b", 31 | "end": "^\\s*//\\s*#?endregion\\b" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /editors/code/src/persistent_state.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { log } from './util'; 3 | 4 | export class PersistentState { 5 | constructor(private readonly globalState: vscode.Memento) { 6 | const { lastCheck, releaseId } = this; 7 | log.info("PersistentState:", { lastCheck, releaseId }); 8 | } 9 | 10 | get lastCheck(): number | undefined { 11 | return this.globalState.get("lastCheck"); 12 | } 13 | 14 | async updateLastCheck(value: number) { 15 | await this.globalState.update("lastCheck", value); 16 | } 17 | 18 | get releaseId(): number | undefined { 19 | return this.globalState.get("releaseId"); 20 | } 21 | 22 | async updateReleaseId(value: number) { 23 | await this.globalState.update("releaseId", value); 24 | } 25 | } -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_await.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("(42).await"); 7 | rt::("self.await"); 8 | rt::("test.await"); 9 | } 10 | 11 | /// An await expression. 12 | /// 13 | /// * `.await`. 14 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 15 | #[non_exhaustive] 16 | pub struct ExprAwait { 17 | /// Attributes associated with expression. 18 | #[rune(iter)] 19 | pub attributes: Vec, 20 | /// The expression being awaited. 21 | pub expr: Box, 22 | /// The dot separating the expression. 23 | pub dot: T![.], 24 | /// The await token. 25 | pub await_token: T![await], 26 | } 27 | 28 | expr_parse!(Await, ExprAwait, ".await expression"); 29 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_continue.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("continue"); 7 | rt::("continue 'foo"); 8 | } 9 | 10 | /// A `continue` statement. 11 | /// 12 | /// * `continue [label]`. 13 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 14 | #[rune(parse = "meta_only")] 15 | #[non_exhaustive] 16 | pub struct ExprContinue { 17 | /// The attributes of the `break` expression 18 | #[rune(iter, meta)] 19 | pub attributes: Vec, 20 | /// The return token. 21 | pub continue_token: T![continue], 22 | /// An optional label to continue to. 23 | #[rune(iter)] 24 | pub label: Option, 25 | } 26 | 27 | expr_parse!(Continue, ExprContinue, "continue expression"); 28 | -------------------------------------------------------------------------------- /crates/rune/tests/esoteric_impls.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn impl_in_other_mod() { 3 | struct Foo; 4 | 5 | mod lol { 6 | use super::Foo; 7 | 8 | impl Foo { 9 | fn lol(self) { 10 | 2 11 | } 12 | } 13 | } 14 | 15 | assert_eq!(Foo.lol(), 2); 16 | } 17 | 18 | #[test] 19 | fn impl_in_super() { 20 | struct Foo; 21 | 22 | mod lol { 23 | impl super::Foo { 24 | fn lol(self) { 25 | 3 26 | } 27 | } 28 | } 29 | 30 | assert_eq!(Foo.lol(), 3); 31 | } 32 | 33 | #[test] 34 | fn impl_in_block() { 35 | struct Foo; 36 | 37 | let value = { 38 | impl Foo { 39 | fn lol(self) { 40 | 4 41 | } 42 | } 43 | }; 44 | 45 | assert_eq!(Foo.lol(), 4); 46 | } 47 | -------------------------------------------------------------------------------- /editors/code/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Run Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "args": [ 9 | "--extensionDevelopmentPath=${workspaceFolder}" 10 | ], 11 | "outFiles": [ 12 | "${workspaceFolder}/dist/**/*.js" 13 | ], 14 | "preLaunchTask": "${defaultBuildTask}" 15 | }, 16 | { 17 | "name": "Extension Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "args": [ 21 | "--extensionDevelopmentPath=${workspaceFolder}", 22 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 23 | ], 24 | "outFiles": [ 25 | "${workspaceFolder}/out/**/*.js", 26 | "${workspaceFolder}/dist/**/*.js" 27 | ], 28 | "preLaunchTask": "tasks: watch-tests" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune-alloc-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-alloc-macros" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "Macros for alloc crate of the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | [dependencies] 17 | syn = { version = "2.0.16", features = ["full"] } 18 | quote = "1.0.27" 19 | proc-macro2 = "1.0.56" 20 | 21 | [dev-dependencies] 22 | rune = { path = "../rune" } 23 | 24 | [lib] 25 | proc-macro = true 26 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/limit/std.rs: -------------------------------------------------------------------------------- 1 | use core::cell::Cell; 2 | 3 | std::thread_local!(static MEMORY: Cell = const { Cell::new(usize::MAX) }); 4 | 5 | pub(super) fn rune_memory_take(amount: usize) -> bool { 6 | MEMORY.with(|tls| { 7 | let v = tls.get(); 8 | 9 | if v >= amount { 10 | tls.set(v.wrapping_sub(amount)); 11 | true 12 | } else { 13 | false 14 | } 15 | }) 16 | } 17 | 18 | pub(super) fn rune_memory_release(amount: usize) { 19 | MEMORY.with(|tls| { 20 | let v = tls.get(); 21 | tls.set(v.saturating_add(amount)); 22 | }) 23 | } 24 | 25 | pub(super) fn rune_memory_get() -> usize { 26 | MEMORY.with(|tls| tls.get()) 27 | } 28 | 29 | pub(super) fn rune_memory_replace(value: usize) -> usize { 30 | MEMORY.with(|tls| tls.replace(value)) 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/benches/primes.rn: -------------------------------------------------------------------------------- 1 | const MAX_NUMBER_TO_CHECK = 10_000; 2 | 3 | #[bench] 4 | pub fn primes(b) { 5 | b.iter( 6 | || { 7 | let prime_mask = []; 8 | 9 | prime_mask.resize(MAX_NUMBER_TO_CHECK, true); 10 | 11 | prime_mask[0] = false; 12 | prime_mask[1] = false; 13 | 14 | let total_primes_found = 0; 15 | 16 | for p in 2..MAX_NUMBER_TO_CHECK { 17 | if prime_mask[p] { 18 | total_primes_found += 1; 19 | let i = 2 * p; 20 | 21 | while i < MAX_NUMBER_TO_CHECK { 22 | prime_mask[i] = false; 23 | i += p; 24 | } 25 | } 26 | } 27 | 28 | total_primes_found 29 | }, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/src/parse/id.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use core::num::NonZeroU32; 3 | 4 | use crate as rune; 5 | use crate::alloc::prelude::*; 6 | 7 | /// A non-zero identifier which definitely contains a value. 8 | #[derive(TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 9 | #[try_clone(copy)] 10 | #[repr(transparent)] 11 | pub struct NonZeroId(#[try_clone(copy)] NonZeroU32); 12 | 13 | impl fmt::Display for NonZeroId { 14 | #[inline] 15 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 16 | self.0.fmt(f) 17 | } 18 | } 19 | 20 | impl fmt::Debug for NonZeroId { 21 | #[inline] 22 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 23 | self.0.fmt(f) 24 | } 25 | } 26 | 27 | impl From for NonZeroId { 28 | fn from(value: NonZeroU32) -> Self { 29 | Self(value) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_return.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("return"); 7 | rt::("return 42"); 8 | rt::("#[attr] return 42"); 9 | } 10 | 11 | /// A return expression. 12 | /// 13 | /// * `return [expr]`. 14 | #[derive(Debug, TryClone, Parse, PartialEq, Eq, ToTokens, Spanned)] 15 | #[rune(parse = "meta_only")] 16 | #[non_exhaustive] 17 | pub struct ExprReturn { 18 | /// The attributes of the `return` statement. 19 | #[rune(iter, meta)] 20 | pub attributes: Vec, 21 | /// The return token. 22 | pub return_token: T![return], 23 | /// An optional expression to return. 24 | #[rune(iter)] 25 | pub expr: Option>, 26 | } 27 | 28 | expr_parse!(Return, ExprReturn, "return expression"); 29 | -------------------------------------------------------------------------------- /scripts/async.rn: -------------------------------------------------------------------------------- 1 | struct Timeout; 2 | 3 | async fn test(timeout, helpful_hint) { 4 | let request = http::get(`http://httpstat.us/200?sleep=${timeout}`); 5 | let timeout = time::sleep(time::Duration::from_secs(2)); 6 | 7 | let result = select { 8 | _ = timeout => Err(Timeout), 9 | res = request => res, 10 | }?; 11 | 12 | Ok((result.text().await?, helpful_hint)) 13 | } 14 | 15 | let a = test(1000, "first call"); 16 | let b = test(5000, "second call"); 17 | 18 | loop { 19 | let res = select { 20 | res = a => res, 21 | res = b => res, 22 | }; 23 | 24 | match res { 25 | () => break, 26 | Ok((text, helpful_hint)) => { 27 | println!("{text}: {helpful_hint}"); 28 | } 29 | Err(Timeout) => { 30 | println!("request timed out"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/rune-tracing-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-tracing-macros" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "Macros for tracing the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | [dependencies] 17 | syn = { version = "2.0.16", features = ["full"] } 18 | quote = { version = "1.0.27" } 19 | proc-macro2 = { version = "1.0.56" } 20 | 21 | [lib] 22 | proc-macro = true 23 | 24 | [dev-dependencies] 25 | rune = { path = "../rune" } 26 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_index.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("value[42]"); 7 | rt::("value[value2[v + 2]]"); 8 | } 9 | 10 | /// An index get operation. 11 | /// 12 | /// * `[]`. 13 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 14 | #[non_exhaustive] 15 | pub struct ExprIndex { 16 | /// Attributes associated with expression. 17 | #[rune(iter)] 18 | pub attributes: Vec, 19 | /// The target of the index set. 20 | pub target: Box, 21 | /// The opening bracket. 22 | pub open: T!['['], 23 | /// The indexing expression. 24 | pub index: Box, 25 | /// The closening bracket. 26 | pub close: T![']'], 27 | } 28 | 29 | expr_parse!(Index, ExprIndex, "index expression"); 30 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_yield.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("yield"); 7 | rt::("yield 42"); 8 | rt::("#[attr] yield 42"); 9 | } 10 | 11 | /// A `yield` expression to return a value from a generator. 12 | /// 13 | /// * `yield [expr]`. 14 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 15 | #[rune(parse = "meta_only")] 16 | #[non_exhaustive] 17 | pub struct ExprYield { 18 | /// The attributes of the `yield` 19 | #[rune(iter, meta)] 20 | pub attributes: Vec, 21 | /// The return token. 22 | pub yield_token: T![yield], 23 | /// An optional expression to yield. 24 | #[rune(iter)] 25 | pub expr: Option>, 26 | } 27 | 28 | expr_parse!(Yield, ExprYield, "yield expression"); 29 | -------------------------------------------------------------------------------- /crates/rune/tests/typed_tuple.rn: -------------------------------------------------------------------------------- 1 | 2 | struct MyType0(a, b); 3 | 4 | enum MyType1 { 5 | A(a, b), 6 | C(c), 7 | } 8 | 9 | enum MyType2 { 10 | A(a, b), 11 | C(c), 12 | } 13 | 14 | enum MyType3 { 15 | A(a, b), 16 | C(c), 17 | } 18 | 19 | #[test] 20 | fn test_defined_tuple() { 21 | let out = match MyType0(1, 2) { 22 | MyType0(a, b) => a + b, 23 | _ => 0, 24 | }; 25 | assert_eq!(out, 3); 26 | 27 | let out = match MyType1::A(1, 2) { 28 | MyType1::A(a, b) => a + b, 29 | _ => 0, 30 | }; 31 | assert_eq!(out, 3); 32 | 33 | let out = match MyType2::C(4) { 34 | MyType2::A(a, b) => a + b, 35 | _ => 0, 36 | }; 37 | assert_eq!(out, 0); 38 | 39 | let out = match MyType3::C(4) { 40 | MyType3::C(a) => a, 41 | _ => 0, 42 | }; 43 | assert_eq!(out, 4); 44 | } 45 | -------------------------------------------------------------------------------- /crates/rune/src/ast/condition.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("true"); 7 | rt::("let [a, ..] = v"); 8 | } 9 | 10 | /// The condition in an if statement. 11 | /// 12 | /// * `true`. 13 | /// * `let Some() = `. 14 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 15 | #[non_exhaustive] 16 | pub enum Condition { 17 | /// A regular expression. 18 | Expr(ast::Expr), 19 | /// A pattern match. 20 | ExprLet(ast::ExprLet), 21 | } 22 | 23 | impl Parse for Condition { 24 | fn parse(p: &mut Parser<'_>) -> Result { 25 | Ok(match p.nth(0)? { 26 | K![let] => Self::ExprLet(ast::ExprLet::parse_without_eager_brace(p)?), 27 | _ => Self::Expr(ast::Expr::parse_without_eager_brace(p)?), 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/function.html.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout}} 2 | 3 | 5 |
6 | {{#if is_test}}
#[test]
{{/if}} 7 | {{#if is_bench}}
#[bench]
{{/if}} 8 | {{#if is_async}}async {{/if}} 9 | fn 10 | {{name}}({{literal args}}){{#if this.return_type}} -> {{literal this.return_type}}{{/if}} 11 |
12 | 13 | {{#if deprecated}}
Deprecated:{{deprecated}}
{{/if}} 14 | {{#if doc}}{{literal doc}}{{/if}} 15 | {{/layout}} 16 | -------------------------------------------------------------------------------- /site/templates/post.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "macros.html" as macros %} 3 | 4 | {% block header %} 5 |
6 | 9 | 10 | {{ macros::nav() }} 11 |
12 | {% endblock header %} 13 | 14 | {% block content %} 15 |
16 |
17 | {% block post %} 18 |

{{ page.title }}

19 | {{ macros::frontmatter(classes="frontmatter-page", author=page.extra.author, date=page.date, word_count=page.word_count, read_time=page.reading_time) }} 20 | {{ page.content | safe }} 21 | {% endblock post %} 22 |
23 |
24 | {% endblock content %} 25 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/testing/rng.rs: -------------------------------------------------------------------------------- 1 | /// XorShiftRng 2 | pub struct DeterministicRng { 3 | count: usize, 4 | x: u32, 5 | y: u32, 6 | z: u32, 7 | w: u32, 8 | } 9 | 10 | impl DeterministicRng { 11 | pub fn new() -> Self { 12 | DeterministicRng { 13 | count: 0, 14 | x: 0x193a6754, 15 | y: 0xa8a7d469, 16 | z: 0x97830e05, 17 | w: 0x113ba7bb, 18 | } 19 | } 20 | 21 | /// Guarantees that each returned number is unique. 22 | pub fn next(&mut self) -> u32 { 23 | self.count += 1; 24 | assert!(self.count <= 70029); 25 | let x = self.x; 26 | let t = x ^ (x << 11); 27 | self.x = self.y; 28 | self.y = self.z; 29 | self.z = self.w; 30 | let w_ = self.w; 31 | self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); 32 | self.w 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_patterns.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn illegal_pattern_in_match() -> rune::support::Result<()> { 7 | assert_errors! { 8 | r#" 9 | struct Foo { bar, baz } 10 | match () { Foo {} => {} } 11 | "#, 12 | span!(52, 58), PatternMissingFields { fields, .. } => { 13 | assert_eq!(fields.len(), 2); 14 | assert_eq!(fields[0].as_ref(), "bar"); 15 | assert_eq!(fields[1].as_ref(), "baz"); 16 | } 17 | }; 18 | 19 | assert_errors! { 20 | r#" 21 | struct Foo { bar, baz } 22 | match () { Foo { bar } => {} } 23 | "#, 24 | span!(52, 63), PatternMissingFields { fields, .. } => { 25 | assert_eq!(fields.len(), 1); 26 | assert_eq!(fields[0].as_ref(), "baz"); 27 | } 28 | }; 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/tests/blocks.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn block_break() { 3 | let value = 0; 4 | 5 | let out = 'block1: { 6 | if value == 0 { 7 | break 'block1 10; 8 | } 9 | 10 | 77 11 | }; 12 | 13 | assert_eq!(out, 10); 14 | } 15 | 16 | #[test] 17 | fn block_inner_break() { 18 | let value = 0; 19 | 20 | let out = 'block1: { 21 | 'block2: { 22 | if value == 0 { 23 | break 'block1 10; 24 | } 25 | } 26 | 27 | 77 28 | }; 29 | 30 | assert_eq!(out, 10); 31 | } 32 | 33 | #[test] 34 | fn block_inner_break2() { 35 | let value = 0; 36 | 37 | let out = 'block1: { 38 | let value = 'block2: { 39 | if value == 0 { 40 | break 'block2 10; 41 | } 42 | }; 43 | 44 | 77 + value 45 | }; 46 | 47 | assert_eq!(out, 87); 48 | } 49 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/callable.rs: -------------------------------------------------------------------------------- 1 | //! A trait used for types which can be called. 2 | //! 3 | //! This trait allows for memory [`limits`] and [`budgets`] to be combined. 4 | //! 5 | //! [`limits`]: crate::limit 6 | //! [`budgets`]: ../../runtime/budget/index.html 7 | 8 | /// A trait used for types which can be called. 9 | /// 10 | /// This trait allows for memory [`limits`] and [`budgets`] to be combined. 11 | /// 12 | /// [`limits`]: crate::limit 13 | /// [`budgets`]: ../../runtime/budget/index.html 14 | pub trait Callable { 15 | /// Output of the callable. 16 | type Output; 17 | 18 | /// Call and consume the callable. 19 | fn call(self) -> Self::Output; 20 | } 21 | 22 | /// Blanket implementation for closures. 23 | impl Callable for T 24 | where 25 | T: FnOnce() -> O, 26 | { 27 | type Output = O; 28 | 29 | fn call(self) -> Self::Output { 30 | self() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/rune/src/tests/wildcard_imports.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_wildcard_precedence() { 5 | rune_assert! { 6 | mod a { pub struct Foo; } 7 | mod b { pub struct Foo; } 8 | use {a::*, b::*}; 9 | use b::Foo; 10 | Foo is b::Foo 11 | }; 12 | 13 | rune_assert! { 14 | mod a { pub struct Foo; } 15 | mod b { pub struct Foo; } 16 | use {b::*, a::*}; 17 | use a::Foo; 18 | Foo is a::Foo 19 | }; 20 | 21 | rune_assert! { 22 | mod a { pub struct Foo; } 23 | mod b { pub struct Foo; } 24 | use a::*; 25 | use b::*; 26 | use a::Foo; 27 | Foo is a::Foo 28 | }; 29 | 30 | rune_assert! { 31 | mod a { pub struct Foo; } 32 | mod b { pub struct Foo; } 33 | use a::Foo; 34 | use a::*; 35 | use b::*; 36 | Foo is a::Foo 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_try.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use core::ops::ControlFlow; 4 | 5 | #[test] 6 | fn custom_try() -> Result<()> { 7 | #[derive(Any)] 8 | struct CustomResult(bool); 9 | 10 | let mut module = Module::new(); 11 | 12 | module.ty::()?; 13 | 14 | module.associated_function(&Protocol::TRY, |r: CustomResult| { 15 | if r.0 { 16 | ControlFlow::Continue(42i64) 17 | } else { 18 | ControlFlow::Break(Err::(0i64)) 19 | } 20 | })?; 21 | 22 | let n: u32 = rune_n! { 23 | mod module, 24 | (CustomResult(true),), 25 | pub fn main(r) { r? } 26 | }; 27 | 28 | assert_eq!(n, 42); 29 | 30 | let result: Result<(), i64> = rune_n! { 31 | mod module, 32 | (CustomResult(false),), 33 | pub fn main(r) { r? } 34 | }; 35 | 36 | assert_eq!(result, Err(0)); 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_call.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("test()"); 7 | rt::("(foo::bar)()"); 8 | } 9 | 10 | /// A call expression. 11 | /// 12 | /// * `()`. 13 | #[derive(Debug, TryClone, Parse, PartialEq, Eq, ToTokens, Spanned)] 14 | #[rune(parse = "meta_only")] 15 | #[non_exhaustive] 16 | pub struct ExprCall { 17 | /// Attributes associated with expression. 18 | #[rune(iter, meta)] 19 | pub attributes: Vec, 20 | /// The name of the function being called. 21 | #[rune(meta)] 22 | pub expr: Box, 23 | /// The arguments of the function call. 24 | pub args: ast::Parenthesized, 25 | /// Opaque identifier related with call. 26 | #[rune(skip)] 27 | pub(crate) id: ItemId, 28 | } 29 | 30 | expr_parse!(Call, ExprCall, "call expression"); 31 | -------------------------------------------------------------------------------- /crates/rune/src/musli.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod ordering { 2 | use core::cmp::Ordering; 3 | 4 | use musli::{Context, Decoder, Encoder}; 5 | 6 | pub(crate) fn encode(value: &Ordering, encoder: E) -> Result<(), E::Error> 7 | where 8 | E: Encoder, 9 | { 10 | match value { 11 | Ordering::Less => encoder.encode_i8(-1), 12 | Ordering::Equal => encoder.encode_i8(0), 13 | Ordering::Greater => encoder.encode_i8(1), 14 | } 15 | } 16 | 17 | pub(crate) fn decode<'de, D>(decoder: D) -> Result 18 | where 19 | D: Decoder<'de>, 20 | { 21 | let cx = decoder.cx(); 22 | 23 | match decoder.decode_i8()? { 24 | -1 => Ok(Ordering::Less), 25 | 0 => Ok(Ordering::Equal), 26 | 1 => Ok(Ordering::Greater), 27 | _ => Err(cx.message("invalid ordering")), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/rune-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-cli" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "An interpreter for the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | default-run = "rune" 17 | 18 | [dependencies] 19 | rune = { version = "0.14.0", path = "../rune", features = ["cli", "tracing"] } 20 | rune-modules = { version = "0.14.0", path = "../rune-modules", features = ["full"] } 21 | 22 | [build-dependencies] 23 | anyhow = "1.0.71" 24 | 25 | [[bin]] 26 | name = "rune" 27 | path = "src/main.rs" 28 | -------------------------------------------------------------------------------- /crates/rune-tracing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-tracing" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "Rune tracing shims for the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | [features] 17 | default = [] 18 | enabled = ["dep:tracing"] 19 | tracing = [] 20 | 21 | [dependencies] 22 | rune-tracing-macros = { path = "../rune-tracing-macros", version = "=0.14.0", default-features = false } 23 | 24 | tracing = { version = "0.1.37", default-features = false, optional = true, features = ["attributes"] } 25 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_break.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("break"); 7 | rt::("break 42"); 8 | rt::("#[attr] break 42"); 9 | } 10 | 11 | /// A break expression. 12 | /// 13 | /// * `break [expr]`. 14 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 15 | #[rune(parse = "meta_only")] 16 | #[non_exhaustive] 17 | pub struct ExprBreak { 18 | /// The attributes of the `break` expression 19 | #[rune(iter, meta)] 20 | pub attributes: Vec, 21 | /// The return token. 22 | pub break_token: T![break], 23 | /// A label to break to. 24 | #[rune(iter)] 25 | pub label: Option, 26 | /// An expression to break with. 27 | #[rune(iter)] 28 | pub expr: Option>, 29 | } 30 | 31 | expr_parse!(Break, ExprBreak, "break expression"); 32 | -------------------------------------------------------------------------------- /editors/code/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$ts-webpack-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never", 13 | "group": "watchers" 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | }, 20 | { 21 | "type": "npm", 22 | "script": "watch-tests", 23 | "problemMatcher": "$tsc-watch", 24 | "isBackground": true, 25 | "presentation": { 26 | "reveal": "never", 27 | "group": "watchers" 28 | }, 29 | "group": "build" 30 | }, 31 | { 32 | "label": "tasks: watch-tests", 33 | "dependsOn": [ 34 | "npm: watch", 35 | "npm: watch-tests" 36 | ], 37 | "problemMatcher": [] 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /crates/rune/src/tests/vm_test_instance_fns.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_instance_kinds() { 5 | let out: (i64, i64, i64, i64) = rune! { 6 | struct Foo { 7 | n, 8 | } 9 | 10 | impl Foo { 11 | fn test(self, n) { 12 | self.n + 1 13 | } 14 | } 15 | 16 | enum Custom { 17 | A(n), 18 | B { 19 | n 20 | }, 21 | C, 22 | } 23 | 24 | impl Custom { 25 | fn test(self) { 26 | match self { 27 | Custom::A(n) => n + 1, 28 | Custom::B{n} => n + 1, 29 | Custom::C => 7, 30 | } 31 | } 32 | } 33 | 34 | (Foo { n: 3 }.test(1), Custom::A(4).test(), Custom::B{n: 5}.test(), Custom::C.test()) 35 | }; 36 | 37 | assert_eq!(out, (4, 5, 6, 7)); 38 | } 39 | -------------------------------------------------------------------------------- /crates/rune-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-macros" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "Macros for the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | [dependencies] 17 | rune-core = { version = "=0.14.0", path = "../rune-core", features = ["std"] } 18 | syn = { version = "2.0.16", features = ["full"] } 19 | quote = "1.0.27" 20 | proc-macro2 = "1.0.56" 21 | 22 | [lib] 23 | proc-macro = true 24 | 25 | [dev-dependencies] 26 | rune = { path = "../rune" } 27 | rune-core = { path = "../rune-core" } 28 | -------------------------------------------------------------------------------- /editors/code/src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /benches/benches/benchmarks/external_functions.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark external function calls. 2 | 3 | use criterion::Criterion; 4 | 5 | criterion::criterion_group!(benches, external_functions); 6 | 7 | fn external_functions(b: &mut Criterion) { 8 | let mut vm1 = rune_vm! { 9 | fn a() { 10 | 79 11 | } 12 | 13 | fn b(f) { 14 | f() 15 | } 16 | 17 | pub fn main() { 18 | (a, b) 19 | } 20 | }; 21 | 22 | let mut vm2 = rune_vm! { 23 | pub fn main(argument) { 24 | let (a, b) = argument; 25 | assert_eq!(b(a), 79); 26 | } 27 | }; 28 | 29 | let entry = rune::Hash::type_hash(["main"]); 30 | 31 | b.bench_function("external_functions", |b| { 32 | let output = vm1.call(entry, ()).expect("failed to fetch function"); 33 | 34 | b.iter(|| vm2.call(entry, (output.clone(),)).expect("failed call")); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /crates/rune/src/tests/f64.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | #[test] 4 | fn test_f64_ceil() -> Result<()> { 5 | let context = Context::with_default_modules()?; 6 | let value: f64 = run(&context, "(1.0 + f64::EPSILON).ceil()", (), true)?; 7 | assert_eq!(value, 2.0); 8 | 9 | Ok(()) 10 | } 11 | 12 | #[test] 13 | fn test_f64_consts() -> Result<()> { 14 | let context = Context::with_default_modules()?; 15 | let value: f64 = run(&context, "std::f64::consts::PI", (), true)?; 16 | assert_eq!(value, std::f64::consts::PI); 17 | 18 | Ok(()) 19 | } 20 | 21 | #[test] 22 | fn test_f64_trig() -> Result<()> { 23 | let context = Context::with_default_modules()?; 24 | let value: f64 = run( 25 | &context, 26 | r#" 27 | let x = std::f64::consts::FRAC_PI_4; 28 | (x.tan() - 1.0).abs() 29 | "#, 30 | (), 31 | true, 32 | )?; 33 | assert!(value < 1e-14); 34 | 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /site/config.toml: -------------------------------------------------------------------------------- 1 | base_url = "https://rune-rs.github.io" 2 | 3 | title = "The Rune Programming Language" 4 | description="Party dynamically like it's 1995" 5 | default_language = "en" 6 | 7 | generate_feed = true 8 | feed_filename = "rss.xml" 9 | rss_limit = 20 10 | compile_sass = true 11 | highlight_code = true 12 | build_search_index = false 13 | extra_syntaxes = ["syntaxes"] 14 | 15 | taxonomies = [ 16 | { name = "categories", feed = true, render = false }, 17 | { name = "tags", feed = true, render = false }, 18 | ] 19 | 20 | [markdown] 21 | highlight_theme = "kronuz" 22 | highlight_code = true 23 | 24 | [extra] 25 | profile = "logo.png" 26 | github = "rune-rs" 27 | discord = "https://discord.gg/v5AeNkT" 28 | book = "rune-rs.github.io/book/" 29 | playground = """ 30 | fn fib(n) { 31 | if n <= 1 { 32 | n 33 | } else { 34 | fib(n - 1) + fib(n - 2) 35 | } 36 | } 37 | 38 | pub fn main() { 39 | fib(15) 40 | } 41 | """ 42 | -------------------------------------------------------------------------------- /crates/rune/src/modules/collections/mod.rs: -------------------------------------------------------------------------------- 1 | //! Dynamic collections. 2 | 3 | pub(crate) mod hash_map; 4 | pub(crate) use hash_map::HashMap; 5 | 6 | pub(crate) mod hash_set; 7 | pub(crate) use hash_set::HashSet; 8 | 9 | pub(crate) mod vec_deque; 10 | pub(crate) use vec_deque::VecDeque; 11 | 12 | use crate as rune; 13 | use crate::{ContextError, Module}; 14 | 15 | /// Module defining collections. 16 | #[rune::module(::std::collections)] 17 | pub fn module() -> Result { 18 | let mut m = Module::from_meta(self::module__meta)?; 19 | 20 | m.reexport( 21 | ["HashMap"], 22 | rune::item!(::std::collections::hash_map::HashMap), 23 | )?; 24 | 25 | m.reexport( 26 | ["HashSet"], 27 | rune::item!(::std::collections::hash_set::HashSet), 28 | )?; 29 | 30 | m.reexport( 31 | ["VecDeque"], 32 | rune::item!(::std::collections::vec_deque::VecDeque), 33 | )?; 34 | 35 | Ok(m) 36 | } 37 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_literals.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn number_literals_oob() { 7 | assert_parse!("-9223372036854775808"); 8 | assert_parse!("-0b1000000000000000000000000000000000000000000000000000000000000000"); 9 | assert_parse!("0b0111111111111111111111111111111111111111111111111111111111111111"); 10 | 11 | assert_errors! { 12 | "-0aardvark", 13 | span!(1, 10), BadNumberLiteral 14 | }; 15 | 16 | assert_errors! { 17 | "-9223372036854775809", 18 | span!(0, 20), BadSignedOutOfBounds { .. } 19 | }; 20 | 21 | assert_parse!("9223372036854775807"); 22 | assert_errors! { 23 | "9223372036854775808", 24 | span!(0, 19), BadSignedOutOfBounds { .. } 25 | }; 26 | 27 | assert_errors! { 28 | "0b1000000000000000000000000000000000000000000000000000000000000000", 29 | span!(0, 66), BadSignedOutOfBounds { .. } 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_loop.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("loop {}"); 7 | rt::("loop { 1; }"); 8 | rt::("'label: loop {1;}"); 9 | rt::("#[attr] 'label: loop {x();}"); 10 | } 11 | 12 | /// A `loop` expression. 13 | /// 14 | /// * `loop { ... }`. 15 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 16 | #[rune(parse = "meta_only")] 17 | #[non_exhaustive] 18 | pub struct ExprLoop { 19 | /// The attributes for the `loop` 20 | #[rune(iter, meta)] 21 | pub attributes: Vec, 22 | /// A label followed by a colon. 23 | #[rune(iter, meta)] 24 | pub label: Option<(ast::Label, T![:])>, 25 | /// The `loop` keyword. 26 | pub loop_token: T![loop], 27 | /// The body of the loop. 28 | pub body: Box, 29 | } 30 | 31 | expr_parse!(Loop, ExprLoop, "loop expression"); 32 | -------------------------------------------------------------------------------- /crates/rune/src/serde.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod ordering { 2 | use core::cmp::Ordering; 3 | 4 | use serde::{Deserialize, Deserializer, Serializer}; 5 | 6 | pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result 7 | where 8 | D: Deserializer<'de>, 9 | { 10 | match i8::deserialize(deserializer)? { 11 | -1 => Ok(Ordering::Less), 12 | 0 => Ok(Ordering::Equal), 13 | 1 => Ok(Ordering::Greater), 14 | _ => Err(serde::de::Error::custom("invalid ordering")), 15 | } 16 | } 17 | 18 | pub(crate) fn serialize(ordering: &Ordering, serializer: S) -> Result 19 | where 20 | S: Serializer, 21 | { 22 | match ordering { 23 | Ordering::Less => serializer.serialize_i8(-1), 24 | Ordering::Equal => serializer.serialize_i8(0), 25 | Ordering::Greater => serializer.serialize_i8(1), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /book/src/structs.md: -------------------------------------------------------------------------------- 1 | # Structs 2 | 3 | Structs are like objects, except that they have a predefined structure with a 4 | set of keys that are known at compile time and guaranteed to be defined. 5 | 6 | Structs can also, like most types, have an `impl` block associated with them 7 | which creates instance functions that you can call on an instance of that 8 | struct. 9 | 10 | ```rune 11 | {{#include ../../scripts/book/structs/user_database.rn}} 12 | ``` 13 | 14 | ```text 15 | $> cargo run -- run scripts/book/structs/user_database.rn 16 | setbac is inactive 17 | setbac is active 18 | ``` 19 | 20 | Structs can also be pattern matched, like most types. 21 | 22 | But since the fields of a struct are known at compile time, the compiler can 23 | ensure that you're only using fields which are defined. 24 | 25 | ```rune 26 | {{#include ../../scripts/book/structs/struct_matching.rn}} 27 | ``` 28 | 29 | ```text 30 | $> cargo run -- run scripts/book/structs/struct_matching.rn 31 | Yep, it's setbac. 32 | Other user: newt. 33 | ``` 34 | -------------------------------------------------------------------------------- /crates/rune/src/tests/moved.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_closure_moved() { 7 | assert_errors!( 8 | r#" 9 | pub fn main() { 10 | let o = []; 11 | let a = move || { 12 | o.push(42); 13 | o 14 | }; 15 | 16 | o.push(42); 17 | a() 18 | } 19 | "#, 20 | span!(153, 154), 21 | VariableMoved { 22 | moved_at: span!(69, 138) 23 | } 24 | ) 25 | } 26 | 27 | #[test] 28 | fn test_async_moved() { 29 | assert_errors!( 30 | r#" 31 | pub async fn main() { 32 | let o = []; 33 | let a = async move { 34 | o.push(42); 35 | o 36 | }; 37 | 38 | o.push(42); 39 | a.await 40 | } 41 | "#, 42 | span!(162, 163), 43 | VariableMoved { 44 | moved_at: span!(75, 147) 45 | } 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/iter/try_cloned.rs: -------------------------------------------------------------------------------- 1 | use crate::clone::TryClone; 2 | use crate::error::Error; 3 | 4 | /// An iterator that clones the elements of an underlying iterator. 5 | /// 6 | /// This `struct` is created by the [`try_cloned`] method on [`IteratorExt`]. 7 | /// See its documentation for more. 8 | /// 9 | /// [`try_cloned`]: crate::iter::IteratorExt::try_cloned 10 | /// [`IteratorExt`]: crate::iter::IteratorExt 11 | pub struct TryCloned { 12 | it: I, 13 | } 14 | 15 | impl TryCloned { 16 | pub(in crate::iter) fn new(it: I) -> Self { 17 | Self { it } 18 | } 19 | } 20 | 21 | impl<'a, I, T> Iterator for TryCloned 22 | where 23 | I: Iterator, 24 | T: 'a + TryClone, 25 | { 26 | type Item = Result; 27 | 28 | #[inline] 29 | fn next(&mut self) -> Option { 30 | Some(self.it.next()?.try_clone()) 31 | } 32 | 33 | #[inline] 34 | fn size_hint(&self) -> (usize, Option) { 35 | self.it.size_hint() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/limit/no_std.rs: -------------------------------------------------------------------------------- 1 | pub(super) fn rune_memory_take(amount: usize) -> bool { 2 | // SAFETY: implementor is expected to have read the documentation and 3 | // implemented this correctly. 4 | unsafe { crate::no_std::__rune_alloc_memory_take(amount) } 5 | } 6 | 7 | pub(super) fn rune_memory_release(amount: usize) { 8 | // SAFETY: implementor is expected to have read the documentation and 9 | // implemented this correctly. 10 | unsafe { crate::no_std::__rune_alloc_memory_release(amount) } 11 | } 12 | 13 | pub(super) fn rune_memory_get() -> usize { 14 | // SAFETY: implementor is expected to have read the documentation and 15 | // implemented this correctly. 16 | unsafe { crate::no_std::__rune_alloc_memory_get() } 17 | } 18 | 19 | pub(super) fn rune_memory_replace(value: usize) -> usize { 20 | // SAFETY: implementor is expected to have read the documentation and 21 | // implemented this correctly. 22 | unsafe { crate::no_std::__rune_alloc_memory_replace(value) } 23 | } 24 | -------------------------------------------------------------------------------- /crates/rune/tests/basics.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn local_assignments() { 3 | let n = 0; 4 | 5 | while n < 10 { 6 | n += 1; 7 | } 8 | 9 | assert_eq!(n, 10); 10 | } 11 | 12 | #[test] 13 | fn call_function() { 14 | fn foo(v) { 15 | v 16 | } 17 | 18 | assert_eq!(foo(42), 42); 19 | assert_ne!(foo(42), 43); 20 | } 21 | 22 | #[test] 23 | fn instance() { 24 | struct Foo { 25 | n, 26 | } 27 | 28 | impl Foo { 29 | fn test(self, n) { 30 | self.n + n 31 | } 32 | } 33 | 34 | let foo = Foo { n: 42 }; 35 | assert_eq!(foo.test(10), 52); 36 | } 37 | 38 | #[test] 39 | fn generator() { 40 | fn foo() { 41 | yield 10; 42 | yield 20; 43 | } 44 | 45 | let n = 0; 46 | 47 | for v in foo() { 48 | n += v; 49 | } 50 | 51 | assert_eq!(n, 30); 52 | } 53 | 54 | #[test] 55 | fn stack_allocations() { 56 | let a = [1, 2].iter().collect::(); 57 | let b = [1, 2]; 58 | assert_eq!(a, b); 59 | } 60 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/btree/mod.rs: -------------------------------------------------------------------------------- 1 | mod append; 2 | mod borrow; 3 | mod fix; 4 | pub mod map; 5 | mod mem; 6 | mod merge_iter; 7 | mod navigate; 8 | mod node; 9 | mod remove; 10 | mod search; 11 | pub mod set; 12 | mod set_val; 13 | mod split; 14 | 15 | use core::cmp::Ordering; 16 | 17 | use crate::alloc::AllocError; 18 | 19 | trait Recover { 20 | type Key; 21 | 22 | fn get( 23 | &self, 24 | cx: &mut C, 25 | key: &Q, 26 | cmp: fn(&mut C, &Q, &Q) -> Result, 27 | ) -> Result, E>; 28 | 29 | fn take( 30 | &mut self, 31 | cx: &mut C, 32 | key: &Q, 33 | cmp: fn(&mut C, &Q, &Q) -> Result, 34 | ) -> Result, E>; 35 | 36 | fn try_replace( 37 | &mut self, 38 | cx: &mut C, 39 | key: Self::Key, 40 | cmp: fn(&mut C, &Q, &Q) -> Result, 41 | ) -> Result, AllocError>, E>; 42 | } 43 | -------------------------------------------------------------------------------- /crates/rune/src/ast/expr_while.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("while x {}"); 7 | rt::("'label: while x {}"); 8 | rt::("#[attr] 'label: while x {}"); 9 | } 10 | 11 | /// A `while` loop. 12 | /// 13 | /// * `while [expr] { ... }`. 14 | #[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] 15 | #[rune(parse = "meta_only")] 16 | #[non_exhaustive] 17 | pub struct ExprWhile { 18 | /// The attributes for the `while` loop 19 | #[rune(iter, meta)] 20 | pub attributes: Vec, 21 | /// A label for the while loop. 22 | #[rune(iter, meta)] 23 | pub label: Option<(ast::Label, T![:])>, 24 | /// The `while` keyword. 25 | pub while_token: T![while], 26 | /// The name of the binding. 27 | pub condition: Box, 28 | /// The body of the while loop. 29 | pub body: Box, 30 | } 31 | 32 | expr_parse!(While, ExprWhile, "while expression"); 33 | -------------------------------------------------------------------------------- /crates/rune/src/workspace/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types for dealing with workspaces of rune code. 2 | 3 | /// The name of the toplevel manifest `Rune.toml`. 4 | pub const MANIFEST_FILE: &str = "Rune.toml"; 5 | 6 | mod glob; 7 | 8 | mod spanned_value; 9 | 10 | mod build; 11 | pub use self::build::{prepare, Build, BuildError}; 12 | 13 | #[cfg(feature = "emit")] 14 | #[cfg_attr(rune_docsrs, doc(cfg(feature = "emit")))] 15 | mod emit; 16 | #[cfg(feature = "emit")] 17 | #[cfg_attr(rune_docsrs, doc(cfg(feature = "emit")))] 18 | #[doc(inline)] 19 | pub use self::emit::EmitError; 20 | 21 | mod error; 22 | pub use self::error::WorkspaceError; 23 | pub(crate) use self::error::WorkspaceErrorKind; 24 | 25 | mod manifest; 26 | pub use self::manifest::{ 27 | Found, FoundKind, FoundPackage, Loader as ManifestLoader, Manifest, Package, WorkspaceFilter, 28 | }; 29 | 30 | mod diagnostics; 31 | pub use self::diagnostics::{Diagnostic, Diagnostics, FatalDiagnostic}; 32 | 33 | mod source_loader; 34 | pub use self::source_loader::{FileSourceLoader, SourceLoader}; 35 | -------------------------------------------------------------------------------- /crates/rune/src/tests/compiler_use.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use ErrorKind::*; 4 | 5 | #[test] 6 | fn test_import_cycle() { 7 | assert_errors! { 8 | r#" 9 | mod a { 10 | pub mod c { pub use super::b::Bar as Baz; } 11 | pub mod b { pub use super::c::Baz as Bar; } 12 | pub use self::b::Bar as Foo; 13 | } 14 | 15 | use self::a::Foo; 16 | "#, 17 | span!(49, 69), ImportCycle { .. } 18 | }; 19 | 20 | assert_errors! { 21 | r#" 22 | mod b { 23 | pub use super::a::Foo; 24 | } 25 | 26 | mod a { 27 | pub use super::b::Foo; 28 | } 29 | 30 | pub fn main() { 31 | a::Foo 32 | } 33 | "#, 34 | span!(161, 167), ImportCycle { path, .. } => { 35 | assert_eq!(3, path.len()); 36 | assert_eq!(span!(99, 112), path[0].location.span); 37 | assert_eq!(span!(37, 50), path[1].location.span); 38 | } 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /crates/rune/src/modules/slice.rs: -------------------------------------------------------------------------------- 1 | //! Types relates to working with slices. 2 | 3 | use crate as rune; 4 | use crate::runtime::slice::Iter; 5 | use crate::{ContextError, Module}; 6 | 7 | /// Types related to working with contiguous slices. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ```rune 12 | /// let it = [10, 20].iter(); 13 | /// 14 | /// assert_eq!(it.next(), Some(10)); 15 | /// assert_eq!(it.next(), Some(20)); 16 | /// assert_eq!(it.next(), None); 17 | /// ``` 18 | #[rune::module(::std::slice)] 19 | pub fn module() -> Result { 20 | let mut m = Module::from_meta(self::module__meta)?; 21 | 22 | m.ty::()?; 23 | m.function_meta(Iter::next__meta)?; 24 | m.function_meta(Iter::size_hint__meta)?; 25 | m.function_meta(Iter::len__meta)?; 26 | m.function_meta(Iter::nth__meta)?; 27 | m.function_meta(Iter::next_back__meta)?; 28 | m.implement_trait::(rune::item!(::std::iter::Iterator))?; 29 | m.implement_trait::(rune::item!(::std::iter::DoubleEndedIterator))?; 30 | 31 | Ok(m) 32 | } 33 | -------------------------------------------------------------------------------- /crates/rune/src/doc/static/layout.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{#each fonts}}{{/each}} 4 | {{#each css}}{{/each}} 5 | {{#each js}}{{/each}} 6 | {{#if search_index}}{{/if}} 7 | 8 | 9 |
10 | 19 | 20 |
21 | {{> @partial-block}} 22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/option/ext.rs: -------------------------------------------------------------------------------- 1 | use crate::clone::TryClone; 2 | use crate::error::Error; 3 | 4 | /// Extensions to `Option`. 5 | pub trait OptionExt { 6 | /// Maps an `Option<&T>` to an `Option` by cloning the contents of the 7 | /// option. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use rune::alloc::prelude::*; 13 | /// 14 | /// let x = 12u32; 15 | /// let opt_x = Some(&x); 16 | /// assert_eq!(opt_x, Some(&12)); 17 | /// let cloned = opt_x.try_cloned()?; 18 | /// assert_eq!(cloned, Some(12u32)); 19 | /// # Ok::<_, rune::alloc::Error>(()) 20 | /// ``` 21 | #[must_use = "`self` will be dropped if the result is not used"] 22 | fn try_cloned(self) -> Result, Error>; 23 | } 24 | 25 | impl OptionExt for Option<&T> 26 | where 27 | T: TryClone, 28 | { 29 | fn try_cloned(self) -> Result, Error> { 30 | Ok(match self { 31 | Some(value) => Some(value.try_clone()?), 32 | None => None, 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/iterator.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc; 2 | use crate::compile::meta; 3 | 4 | use super::{FromValue, MaybeTypeOf, RuntimeError, Value, VmError}; 5 | 6 | /// An owning iterator. 7 | #[derive(Debug)] 8 | pub struct Iterator { 9 | iter: Value, 10 | } 11 | 12 | impl Iterator { 13 | pub(crate) fn new(iter: Value) -> Self { 14 | Self { iter } 15 | } 16 | 17 | #[inline] 18 | pub(crate) fn size_hint(&self) -> Result<(usize, Option), VmError> { 19 | self.iter.protocol_size_hint() 20 | } 21 | 22 | #[inline] 23 | pub(crate) fn next(&mut self) -> Result, VmError> { 24 | self.iter.protocol_next() 25 | } 26 | } 27 | 28 | impl FromValue for Iterator { 29 | #[inline] 30 | fn from_value(value: Value) -> Result { 31 | value.into_iter().map_err(RuntimeError::from) 32 | } 33 | } 34 | 35 | impl MaybeTypeOf for Iterator { 36 | #[inline] 37 | fn maybe_type_of() -> alloc::Result { 38 | Ok(meta::DocType::empty()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /crates/rune-core/src/hash/into_hash.rs: -------------------------------------------------------------------------------- 1 | use crate::hash::Hash; 2 | use crate::protocol::Protocol; 3 | 4 | mod sealed { 5 | use crate::hash::Hash; 6 | use crate::params::Params; 7 | use crate::protocol::Protocol; 8 | 9 | pub trait Sealed {} 10 | 11 | impl Sealed for &str {} 12 | impl Sealed for Hash {} 13 | impl Sealed for &Protocol {} 14 | impl Sealed for Params {} 15 | } 16 | 17 | /// Trait for types which can be converted into a [Hash]. 18 | /// 19 | /// [Hash]: struct@crate::hash::Hash 20 | pub trait IntoHash: self::sealed::Sealed { 21 | /// Convert current type into a hash. 22 | fn into_hash(self) -> Hash; 23 | } 24 | 25 | impl IntoHash for Hash { 26 | #[inline] 27 | fn into_hash(self) -> Hash { 28 | self 29 | } 30 | } 31 | 32 | impl IntoHash for &str { 33 | #[inline] 34 | fn into_hash(self) -> Hash { 35 | Hash::ident(self) 36 | } 37 | } 38 | 39 | impl IntoHash for &Protocol { 40 | #[inline] 41 | fn into_hash(self) -> Hash { 42 | self.hash 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/vec/set_len_on_drop.rs: -------------------------------------------------------------------------------- 1 | // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. 2 | // 3 | // The idea is: The length field in SetLenOnDrop is a local variable 4 | // that the optimizer will see does not alias with any stores through the Vec's data 5 | // pointer. This is a workaround for alias analysis issue #32155 6 | pub(super) struct SetLenOnDrop<'a> { 7 | len: &'a mut usize, 8 | local_len: usize, 9 | } 10 | 11 | impl<'a> SetLenOnDrop<'a> { 12 | #[inline] 13 | pub(super) fn new(len: &'a mut usize) -> Self { 14 | SetLenOnDrop { 15 | local_len: *len, 16 | len, 17 | } 18 | } 19 | 20 | #[inline] 21 | pub(super) fn increment_len(&mut self, increment: usize) { 22 | self.local_len += increment; 23 | } 24 | 25 | #[inline] 26 | pub(super) fn current_len(&self) -> usize { 27 | self.local_len 28 | } 29 | } 30 | 31 | impl Drop for SetLenOnDrop<'_> { 32 | #[inline] 33 | fn drop(&mut self) { 34 | *self.len = self.local_len; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/budget/no_std.rs: -------------------------------------------------------------------------------- 1 | // In no-std environments, the implementor must define these functions. 2 | // 3 | // Normally these make use of thread-local storage, but if you want them to be 4 | // completed disabled simply return dummy values or store it in static storage 5 | // (if singlethreaded). 6 | extern "C" { 7 | /// Get the current budget for the current thread. 8 | pub(super) fn __rune_budget_get() -> usize; 9 | 10 | /// Replace the current budget for the current thread and return the one 11 | /// which was previously set. 12 | pub(super) fn __rune_budget_replace(value: usize) -> usize; 13 | } 14 | 15 | pub(super) fn rune_budget_get() -> usize { 16 | // SAFETY: implementor is expected to have read the documentation and 17 | // implemented this correctly. 18 | unsafe { __rune_budget_get() } 19 | } 20 | 21 | pub(super) fn rune_budget_replace(value: usize) -> usize { 22 | // SAFETY: implementor is expected to have read the documentation and 23 | // implemented this correctly. 24 | unsafe { __rune_budget_replace(value) } 25 | } 26 | -------------------------------------------------------------------------------- /examples/examples/lookup_function.rs: -------------------------------------------------------------------------------- 1 | use rune::sync::Arc; 2 | use rune::{Context, Vm}; 3 | 4 | fn main() -> rune::support::Result<()> { 5 | let context = Context::with_default_modules()?; 6 | let context = Arc::try_new(context.runtime()?)?; 7 | 8 | let mut sources = rune::sources! { 9 | entry => { 10 | pub fn max(a, b) { 11 | if a > b { 12 | a 13 | } else { 14 | b 15 | } 16 | } 17 | } 18 | }; 19 | 20 | let unit = rune::prepare(&mut sources).build()?; 21 | let unit = Arc::try_new(unit)?; 22 | let vm = Vm::new(context, unit); 23 | 24 | // Looking up an item from the source. 25 | let dynamic_max = vm.lookup_function(["max"])?; 26 | 27 | let value = dynamic_max.call::((10, 20))?; 28 | assert_eq!(value, 20); 29 | 30 | let item = rune::item!(::std::i64::max); 31 | let max = vm.lookup_function(item)?; 32 | 33 | let value = max.call::((10, 20))?; 34 | assert_eq!(value, 20); 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /crates/rune-languageserver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-languageserver" 3 | version = "0.14.0" 4 | authors = ["John-John Tedro "] 5 | edition = "2021" 6 | rust-version = "1.91" 7 | description = "A language server for the Rune Language, an embeddable dynamic programming language for Rust." 8 | documentation = "https://docs.rs/rune" 9 | readme = "README.md" 10 | homepage = "https://github.com/rune-rs/rune" 11 | repository = "https://github.com/rune-rs/rune" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["language", "scripting", "scripting-language"] 14 | categories = ["parser-implementations"] 15 | 16 | [dependencies] 17 | tokio = { version = "1.28.1", features = ["full"] } 18 | anyhow = "1.0.71" 19 | tracing = "0.1.37" 20 | tracing-appender = "0.2.2" 21 | tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } 22 | 23 | rune = { version = "0.14.0", path = "../rune", features = ["languageserver", "tracing"] } 24 | rune-modules = { version = "0.14.0", path = "../rune-modules", features = ["full"] } 25 | 26 | [build-dependencies] 27 | anyhow = "1.0.71" 28 | -------------------------------------------------------------------------------- /scripts/controls.rn: -------------------------------------------------------------------------------- 1 | // Testing a bunch of control flows. 2 | 3 | fn test(n) { 4 | if n > 1 { 5 | 2 6 | } else { 7 | if n < 1 { 8 | 0 9 | } else { 10 | 1 11 | } 12 | } 13 | } 14 | 15 | fn test2(n) { 16 | if n > 1 { 17 | 2 18 | } else if n < 1 { 19 | 0 20 | } else { 21 | 1 22 | } 23 | } 24 | 25 | fn test3(n) { 26 | let out = if n > 1 { 27 | 2 28 | } else if n < 1 { 29 | 0 30 | } else { 31 | 1 32 | }; 33 | 34 | out 35 | } 36 | 37 | fn from_loop() { 38 | let n = 1; 39 | 40 | while n < 4 { 41 | n = n + 1; 42 | } 43 | 44 | n 45 | } 46 | 47 | fn returns_unit(n) { 48 | if n > 0 { 49 | let _ = 100; 50 | } 51 | } 52 | 53 | fn returns_string() { 54 | "this is a string" 55 | } 56 | 57 | let a = test(0); 58 | let b = test2(1); 59 | let c = test3(2); 60 | let d = from_loop(); 61 | let e = returns_unit(1); 62 | let f = returns_string(); 63 | 64 | dbg!([0, 1, 2, 4, (), "this is a string"] == [a, b, c, d, e, f]); 65 | -------------------------------------------------------------------------------- /editors/code/src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { Ctx } from "./ctx"; 3 | 4 | let ctx: Ctx | undefined; 5 | 6 | let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null; 7 | 8 | export function traceOutputChannel() { 9 | if (!TRACE_OUTPUT_CHANNEL) { 10 | TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel( 11 | "Rune Language Server Trace" 12 | ); 13 | } 14 | return TRACE_OUTPUT_CHANNEL; 15 | } 16 | 17 | let OUTPUT_CHANNEL: vscode.OutputChannel | null = null; 18 | 19 | export function outputChannel() { 20 | if (!OUTPUT_CHANNEL) { 21 | OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rune Language Server"); 22 | } 23 | 24 | return OUTPUT_CHANNEL; 25 | } 26 | 27 | export async function activate(context: vscode.ExtensionContext) { 28 | if (!ctx) { 29 | ctx = new Ctx(context); 30 | } 31 | 32 | ctx.activate(); 33 | } 34 | 35 | export async function deactivate() { 36 | TRACE_OUTPUT_CHANNEL?.dispose(); 37 | TRACE_OUTPUT_CHANNEL = null; 38 | OUTPUT_CHANNEL?.dispose(); 39 | OUTPUT_CHANNEL = null; 40 | ctx?.dispose(); 41 | ctx = undefined; 42 | } 43 | -------------------------------------------------------------------------------- /crates/rune/src/tests/macros/stringy_math.rs: -------------------------------------------------------------------------------- 1 | use crate as rune; 2 | use crate::ast; 3 | use crate::compile; 4 | use crate::macros::{quote, MacroContext, TokenStream}; 5 | use crate::parse::Parser; 6 | 7 | /// Implementation of the `stringy_math!` macro. 8 | #[rune::macro_] 9 | pub fn stringy_math( 10 | cx: &mut MacroContext<'_, '_, '_>, 11 | stream: &TokenStream, 12 | ) -> compile::Result { 13 | let mut parser = Parser::from_token_stream(stream, cx.input_span()); 14 | 15 | let mut output = quote!(0); 16 | 17 | while !parser.is_eof()? { 18 | let op = parser.parse::()?; 19 | let arg = parser.parse::()?; 20 | 21 | output = match cx.resolve(op)? { 22 | "add" => quote!((#output) + #arg), 23 | "sub" => quote!((#output) - #arg), 24 | "div" => quote!((#output) / #arg), 25 | "mul" => quote!((#output) * #arg), 26 | _ => return Err(compile::Error::msg(op, "unsupported operation")), 27 | } 28 | } 29 | 30 | parser.eof()?; 31 | Ok(output.into_token_stream(cx)?) 32 | } 33 | -------------------------------------------------------------------------------- /crates/rune/src/shared/assert_send.rs: -------------------------------------------------------------------------------- 1 | use core::future::Future; 2 | use core::pin::Pin; 3 | use core::task::{Context, Poll}; 4 | 5 | /// Internal helper struct to assert that a future is send. 6 | #[pin_project::pin_project] 7 | pub(crate) struct AssertSend(#[pin] T); 8 | 9 | impl AssertSend { 10 | /// Assert that the given inner value is `Send` by some external invariant. 11 | /// 12 | /// # Safety 13 | /// 14 | /// ProtocolCaller must assert that nothing is done with inner that violates it 15 | /// being `Send` at runtime. 16 | pub(crate) unsafe fn new(inner: T) -> Self { 17 | Self(inner) 18 | } 19 | } 20 | 21 | // Safety: we wrap all APIs around the [VmExecution], preventing values from 22 | // escaping from contained virtual machine. 23 | unsafe impl Send for AssertSend {} 24 | 25 | impl Future for AssertSend 26 | where 27 | T: Future, 28 | { 29 | type Output = T::Output; 30 | 31 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 32 | let this = self.project(); 33 | this.0.poll(cx) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /crates/rune/src/tests/option.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use VmErrorKind::*; 4 | 5 | #[test] 6 | fn test_map() { 7 | let out: Option = rune!(Some(1).map(|v| v + 1)); 8 | assert_eq!(out, Some(2)) 9 | } 10 | 11 | #[test] 12 | fn test_and_then() { 13 | let out: Option = rune!(Some(1).and_then(|v| Some(v + 1))); 14 | assert_eq!(out, Some(2)) 15 | } 16 | 17 | #[test] 18 | fn test_expect_some() { 19 | let out: i32 = rune!(Some(1).expect("Some")); 20 | assert_eq!(out, 1); 21 | } 22 | 23 | #[test] 24 | fn test_expect() { 25 | assert_vm_error!( 26 | "None.expect(\"None\")", 27 | Panic { reason } => { 28 | assert_eq!(reason.to_string(), "None") 29 | } 30 | ); 31 | } 32 | 33 | #[test] 34 | fn test_unwrap_some() { 35 | let out: i32 = rune!(Some(1).unwrap()); 36 | assert_eq!(out, 1); 37 | } 38 | 39 | #[test] 40 | fn test_unwrap() { 41 | assert_vm_error!( 42 | "None.unwrap()", 43 | Panic { reason} => { 44 | assert_eq!(reason.to_string(), "Called `Option::unwrap()` on a `None` value") 45 | } 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /crates/rune-wasm/src/time.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Promise; 2 | use rune::{Any, ContextError, Module, VmError}; 3 | use wasm_bindgen::prelude::*; 4 | use wasm_bindgen_futures::JsFuture; 5 | 6 | #[wasm_bindgen(module = "/module.js")] 7 | extern "C" { 8 | fn js_sleep(ms: i32) -> Promise; 9 | } 10 | 11 | /// The wasm 'time' module. 12 | pub fn module() -> Result { 13 | let mut m = Module::with_crate("time")?; 14 | m.ty::()?; 15 | m.function("from_secs", Duration::from_secs) 16 | .build_associated::()?; 17 | m.function("sleep", sleep).build()?; 18 | Ok(m) 19 | } 20 | 21 | #[derive(Any)] 22 | #[rune(item = ::time)] 23 | struct Duration(i32); 24 | 25 | impl Duration { 26 | fn from_secs(value: i64) -> Self { 27 | Self(value as i32 * 1000) 28 | } 29 | } 30 | 31 | async fn sleep(duration: Duration) -> Result<(), VmError> { 32 | let promise = js_sleep(duration.0); 33 | let js_fut = JsFuture::from(promise); 34 | 35 | if js_fut.await.is_err() { 36 | return Err(VmError::panic("Sleep errored")); 37 | } 38 | 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /crates/rune/src/ast/rn_type.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::prelude::*; 2 | 3 | #[test] 4 | #[cfg(not(miri))] 5 | fn ast_parse() { 6 | rt::("Bar"); 7 | rt::("one::two::three::four::Five"); 8 | rt::("Self"); 9 | rt::("(one::One, two::Two)"); 10 | rt::("(one::One, (two::Two, three::Three))"); 11 | } 12 | 13 | /// A type, used for static typing. 14 | #[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] 15 | #[non_exhaustive] 16 | pub enum Type { 17 | /// If the type is an identifier or a path. 18 | Path(ast::Path), 19 | /// If the type should return nothing (a.k.a the "never" type in Rust). 20 | Bang(T![!]), 21 | /// If the type is a tuple. 22 | Tuple(ast::Parenthesized, T![,]>), 23 | } 24 | 25 | impl Parse for Type { 26 | fn parse(p: &mut Parser<'_>) -> Result { 27 | let segment = match p.nth(0)? { 28 | K![!] => Self::Bang(p.parse()?), 29 | K!['('] => Self::Tuple(p.parse()?), 30 | _ => Self::Path(p.parse()?), 31 | }; 32 | 33 | Ok(segment) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /editors/code/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /book/src/hot_reloading.md: -------------------------------------------------------------------------------- 1 | # Hot reloading 2 | 3 | Compiling a [`Unit`] and a [`RuntimeContext`] are expensive operations compared 4 | to the cost of calling a function. So you should try to do this as little as 5 | possible. It is appropriate to recompile a script when the source of the script 6 | changes. This section provides you with details for how this can be done when 7 | loading scripts from the filesystem. 8 | 9 | A typical way to accomplish this is to watch a scripts directory using the 10 | [`notify` crate]. This allow the application to generate events whenever changes 11 | to the directory are detected. See the [`hot_reloading` example] and in 12 | particular the [`PathReloader`] type. 13 | 14 | ```rust 15 | {{#include ../../examples/examples/hot_reloading.rs}} 16 | ``` 17 | 18 | [`notify` crate]: https://docs.rs/notify 19 | [`Unit`]: https://docs.rs/rune/latest/rune/runtime/unit/struct.Unit.html 20 | [`hot_reloading` example]: https://github.com/rune-rs/rune/blob/main/examples/examples/hot_reloading.rs 21 | [`PathReloader`]: https://github.com/rune-rs/rune/blob/main/examples/examples/hot_reloading/path_reloader.rs 22 | 23 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/select.rs: -------------------------------------------------------------------------------- 1 | use core::future; 2 | use core::pin::Pin; 3 | use core::task::{ready, Context, Poll}; 4 | 5 | use futures_core::Stream; 6 | use futures_util::stream::FuturesUnordered; 7 | 8 | use crate::runtime::future::SelectFuture; 9 | use crate::runtime::{Future, Mut, Value, VmError}; 10 | 11 | /// A stored select. 12 | #[derive(Debug)] 13 | pub struct Select { 14 | futures: FuturesUnordered>>, 15 | } 16 | 17 | impl Select { 18 | /// Construct a new stored select. 19 | pub(crate) fn new(futures: FuturesUnordered>>) -> Self { 20 | Self { futures } 21 | } 22 | } 23 | 24 | impl future::Future for Select { 25 | type Output = Result<(usize, Value), VmError>; 26 | 27 | #[inline] 28 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 29 | let Some(result) = ready!(Pin::new(&mut self.futures).poll_next(cx)) else { 30 | return Poll::Ready(Err(VmError::panic("select: no futures to select from"))); 31 | }; 32 | 33 | Poll::Ready(result) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tools/site/src/main.rs: -------------------------------------------------------------------------------- 1 | //! A small utility to build the guts of . 2 | 3 | use anyhow::{bail, Result}; 4 | use flate2::read::GzDecoder; 5 | use std::env; 6 | use std::io; 7 | use std::path::Path; 8 | use std::process::Command; 9 | use tar::Archive; 10 | 11 | fn main() -> Result<()> { 12 | let url = match env::var("ZOLA_URL") { 13 | Ok(url) => url, 14 | Err(..) => bail!("missing ZOLA_URL"), 15 | }; 16 | 17 | let target = Path::new("target"); 18 | let bin = target.join("zola"); 19 | 20 | if !bin.is_file() { 21 | println!("Downloading: {url}"); 22 | let bytes = reqwest::blocking::get(&url)?.bytes()?; 23 | let decoder = GzDecoder::new(io::Cursor::new(bytes.as_ref())); 24 | let mut archive = Archive::new(decoder); 25 | archive.unpack(target)?; 26 | } 27 | 28 | if !bin.is_file() { 29 | bail!("Missing bin: {}", bin.display()); 30 | } 31 | 32 | let mut it = env::args(); 33 | it.next(); 34 | 35 | let status = Command::new(bin).args(it).status()?; 36 | std::process::exit(status.code().unwrap()); 37 | } 38 | -------------------------------------------------------------------------------- /crates/rune/tests/select.rn: -------------------------------------------------------------------------------- 1 | async fn foo(n) { 2 | n 3 | } 4 | 5 | #[test] 6 | async fn select_branches() { 7 | let count = 0; 8 | let sum = 0; 9 | 10 | let a = foo(42); 11 | let b = foo(43); 12 | 13 | for _ in 0..4 { 14 | let value = select { 15 | value = a => value, 16 | value = b => value, 17 | }; 18 | 19 | if let () = value { 20 | break; 21 | } 22 | 23 | count += 1; 24 | sum += value; 25 | } 26 | 27 | assert_eq!(count, 2); 28 | assert_eq!(sum, 85); 29 | } 30 | 31 | #[test] 32 | async fn select_with_defaults() { 33 | let count = 0; 34 | let sum = 0; 35 | 36 | let a = foo(42); 37 | let b = foo(43); 38 | 39 | for _ in 0..4 { 40 | let value = select { 41 | value = a => value, 42 | value = b => value, 43 | default => 10, 44 | }; 45 | 46 | if let () = value { 47 | break; 48 | } 49 | 50 | count += 1; 51 | sum += value; 52 | } 53 | 54 | assert_eq!(count, 4); 55 | assert_eq!(sum, 105); 56 | } 57 | --------------------------------------------------------------------------------