├── .gitattributes ├── .github └── workflows │ ├── benchmarks.yml │ ├── ci.yml │ ├── release.yml │ └── site.yml ├── .gitignore ├── .vscode └── launch.json ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── Rune.toml ├── assets ├── icon.png ├── icon.xcf ├── logo.xcf ├── social.png └── tokens.yaml ├── benches ├── Cargo.toml ├── README.md ├── Rune.toml └── benches │ ├── benchmarks │ ├── aoc_2020_11a.rs │ ├── aoc_2020_19b.rs │ ├── aoc_2020_1a.rs │ ├── aoc_2020_1b.rs │ ├── brainfuck.rs │ ├── data │ │ ├── aoc_2020_1.txt │ │ ├── aoc_2020_11a.txt │ │ └── aoc_2020_19b.txt │ ├── external_functions.rs │ └── fib.rs │ ├── comparison.rs │ ├── comparisons │ ├── eval.rs │ └── primes.rs │ └── main.rs ├── book ├── .gitignore ├── README.md ├── book.toml └── src │ ├── SUMMARY.md │ ├── advanced.md │ ├── async.md │ ├── call_frames.md │ ├── closures.md │ ├── compiler_guide.md │ ├── concepts.md │ ├── control_flow.md │ ├── deprecated.md │ ├── drop_order.md │ ├── dynamic_types.md │ ├── enums.md │ ├── external_types.md │ ├── field_functions.md │ ├── foreword.md │ ├── functions.md │ ├── generators.md │ ├── getting_started.md │ ├── highlight.js │ ├── hot_reloading.md │ ├── instance_functions.md │ ├── introduction.md │ ├── items_imports.md │ ├── loops.md │ ├── macros.md │ ├── multithreading.md │ ├── objects.md │ ├── pattern_matching.md │ ├── primitives.md │ ├── safety.md │ ├── sandboxing.md │ ├── streams.md │ ├── string_literals.md │ ├── structs.md │ ├── template_literals.md │ ├── the_stack.md │ ├── traits.md │ ├── try_operator.md │ ├── tuples.md │ ├── types.md │ ├── variables.md │ └── vectors.md ├── crates ├── rune-alloc-macros │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── context.rs │ │ ├── lib.rs │ │ └── try_clone.rs ├── rune-alloc │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── alloc │ │ │ ├── allocator.rs │ │ │ ├── global.rs │ │ │ └── mod.rs │ │ ├── borrow │ │ │ └── mod.rs │ │ ├── boxed.rs │ │ ├── btree │ │ │ ├── append.rs │ │ │ ├── borrow.rs │ │ │ ├── fix.rs │ │ │ ├── map.rs │ │ │ ├── map │ │ │ │ ├── entry.rs │ │ │ │ └── tests.rs │ │ │ ├── mem.rs │ │ │ ├── merge_iter.rs │ │ │ ├── mod.rs │ │ │ ├── navigate.rs │ │ │ ├── node.rs │ │ │ ├── node │ │ │ │ └── tests.rs │ │ │ ├── remove.rs │ │ │ ├── search.rs │ │ │ ├── set.rs │ │ │ ├── set │ │ │ │ └── tests.rs │ │ │ ├── set_val.rs │ │ │ └── split.rs │ │ ├── callable.rs │ │ ├── clone.rs │ │ ├── error.rs │ │ ├── fmt │ │ │ ├── impls.rs │ │ │ └── mod.rs │ │ ├── hashbrown │ │ │ ├── map.rs │ │ │ ├── mod.rs │ │ │ ├── raw │ │ │ │ ├── bitmask.rs │ │ │ │ ├── generic.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── neon.rs │ │ │ │ └── sse2.rs │ │ │ ├── scopeguard.rs │ │ │ ├── serde.rs │ │ │ └── set.rs │ │ ├── hint.rs │ │ ├── iter │ │ │ ├── ext.rs │ │ │ ├── join.rs │ │ │ ├── mod.rs │ │ │ ├── try_cloned.rs │ │ │ ├── try_extend.rs │ │ │ └── try_from_iterator.rs │ │ ├── lib.rs │ │ ├── limit │ │ │ ├── mod.rs │ │ │ ├── no_std.rs │ │ │ └── std.rs │ │ ├── macros.rs │ │ ├── musli.rs │ │ ├── no_std.rs │ │ ├── option │ │ │ ├── ext.rs │ │ │ └── mod.rs │ │ ├── path.rs │ │ ├── ptr.rs │ │ ├── ptr │ │ │ └── unique.rs │ │ ├── public_macros.rs │ │ ├── raw_vec.rs │ │ ├── serde │ │ │ ├── de.rs │ │ │ ├── mod.rs │ │ │ └── ser.rs │ │ ├── slice.rs │ │ ├── slice │ │ │ ├── iter.rs │ │ │ └── iter │ │ │ │ └── macros.rs │ │ ├── str.rs │ │ ├── string │ │ │ ├── mod.rs │ │ │ ├── serde.rs │ │ │ └── try_to_string.rs │ │ ├── testing │ │ │ ├── crash_test.rs │ │ │ ├── mod.rs │ │ │ ├── ord_chaos.rs │ │ │ └── rng.rs │ │ ├── tests.rs │ │ ├── vec │ │ │ ├── drain.rs │ │ │ ├── into_iter.rs │ │ │ ├── is_zero.rs │ │ │ ├── mod.rs │ │ │ ├── partial_eq.rs │ │ │ ├── set_len_on_drop.rs │ │ │ ├── spec_extend.rs │ │ │ ├── spec_from_elem.rs │ │ │ └── splice.rs │ │ └── vec_deque │ │ │ ├── drain.rs │ │ │ ├── into_iter.rs │ │ │ ├── iter.rs │ │ │ ├── iter_mut.rs │ │ │ ├── macros.rs │ │ │ ├── mod.rs │ │ │ └── raw_iter.rs │ ├── third-party │ │ └── .gitignore │ └── tools │ │ └── import.ps1 ├── rune-cli │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ └── main.rs ├── rune-core │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── hash.rs │ │ ├── hash │ │ ├── into_hash.rs │ │ └── to_type_hash.rs │ │ ├── item.rs │ │ ├── item │ │ ├── component.rs │ │ ├── component_ref.rs │ │ ├── internal.rs │ │ ├── into_component.rs │ │ ├── item.rs │ │ ├── item_buf.rs │ │ ├── iter.rs │ │ ├── musli.rs │ │ ├── serde.rs │ │ └── tests.rs │ │ ├── lib.rs │ │ ├── params.rs │ │ └── protocol.rs ├── rune-languageserver │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ └── main.rs ├── rune-macros │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── any.rs │ │ ├── const_value.rs │ │ ├── context.rs │ │ ├── from_value.rs │ │ ├── function.rs │ │ ├── hash.rs │ │ ├── inst_display.rs │ │ ├── item.rs │ │ ├── lib.rs │ │ ├── macro_.rs │ │ ├── module.rs │ │ ├── opaque.rs │ │ ├── parse.rs │ │ ├── path_in.rs │ │ ├── quote.rs │ │ ├── quote │ │ │ ├── builder.rs │ │ │ ├── generated.rs │ │ │ └── inner.rs │ │ ├── spanned.rs │ │ ├── to_tokens.rs │ │ └── to_value.rs │ └── tests │ │ └── derive.rs ├── rune-modules │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── base64.rs │ │ ├── fs.rs │ │ ├── http.rs │ │ ├── json.rs │ │ ├── lib.rs │ │ ├── process.rs │ │ ├── rand │ │ ├── error.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── os_error.rs │ │ ├── os_rng.rs │ │ ├── small_rng.rs │ │ ├── std_rng.rs │ │ ├── thread_rng.rs │ │ └── try_from_rng_error.rs │ │ ├── signal.rs │ │ ├── time.rs │ │ └── toml.rs ├── rune-tracing-macros │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── instrument.rs │ │ └── lib.rs ├── rune-tracing │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── rune-wasm │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── module.js │ ├── package-lock.json │ ├── package.json │ ├── rollup.config.mjs │ ├── rune.js │ └── src │ │ ├── http.rs │ │ ├── lib.rs │ │ └── time.rs └── rune │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── Rune.toml │ ├── benches │ ├── bf.rn │ ├── fib.rn │ ├── nbodies.lua │ ├── nbodies.rn │ └── primes.rn │ ├── src │ ├── ace │ │ ├── autocomplete.rs │ │ ├── mod.rs │ │ └── static │ │ │ ├── rune-completer.js │ │ │ ├── rune-highlight-rules.js │ │ │ └── rune-mode.js │ ├── alloc.rs │ ├── any.rs │ ├── ast │ │ ├── attribute.rs │ │ ├── block.rs │ │ ├── condition.rs │ │ ├── expr.rs │ │ ├── expr_assign.rs │ │ ├── expr_await.rs │ │ ├── expr_binary.rs │ │ ├── expr_block.rs │ │ ├── expr_break.rs │ │ ├── expr_call.rs │ │ ├── expr_closure.rs │ │ ├── expr_continue.rs │ │ ├── expr_empty.rs │ │ ├── expr_field_access.rs │ │ ├── expr_for.rs │ │ ├── expr_group.rs │ │ ├── expr_if.rs │ │ ├── expr_index.rs │ │ ├── expr_let.rs │ │ ├── expr_lit.rs │ │ ├── expr_loop.rs │ │ ├── expr_match.rs │ │ ├── expr_object.rs │ │ ├── expr_range.rs │ │ ├── expr_return.rs │ │ ├── expr_select.rs │ │ ├── expr_try.rs │ │ ├── expr_tuple.rs │ │ ├── expr_unary.rs │ │ ├── expr_vec.rs │ │ ├── expr_while.rs │ │ ├── expr_yield.rs │ │ ├── fields.rs │ │ ├── file.rs │ │ ├── fn_arg.rs │ │ ├── generated.rs │ │ ├── grouped.rs │ │ ├── ident.rs │ │ ├── item.rs │ │ ├── item_const.rs │ │ ├── item_enum.rs │ │ ├── item_fn.rs │ │ ├── item_impl.rs │ │ ├── item_mod.rs │ │ ├── item_struct.rs │ │ ├── item_use.rs │ │ ├── label.rs │ │ ├── lit.rs │ │ ├── lit_bool.rs │ │ ├── lit_byte.rs │ │ ├── lit_byte_str.rs │ │ ├── lit_char.rs │ │ ├── lit_number.rs │ │ ├── lit_str.rs │ │ ├── local.rs │ │ ├── macro_call.rs │ │ ├── macro_utils.rs │ │ ├── mod.rs │ │ ├── pat.rs │ │ ├── path.rs │ │ ├── prelude.rs │ │ ├── rn_type.rs │ │ ├── span.rs │ │ ├── spanned.rs │ │ ├── stmt.rs │ │ ├── testing.rs │ │ ├── tests.rs │ │ ├── to_ast.rs │ │ ├── token.rs │ │ ├── unescape.rs │ │ ├── utils.rs │ │ └── vis.rs │ ├── build.rs │ ├── cli │ │ ├── ace.rs │ │ ├── benches.rs │ │ ├── check.rs │ │ ├── doc.rs │ │ ├── format.rs │ │ ├── languageserver.rs │ │ ├── loader.rs │ │ ├── mod.rs │ │ ├── naming.rs │ │ ├── out.rs │ │ ├── run.rs │ │ ├── tests.rs │ │ └── visitor.rs │ ├── compile │ │ ├── assembly.rs │ │ ├── attrs.rs │ │ ├── compile.rs │ │ ├── compile_visitor.rs │ │ ├── context.rs │ │ ├── context_error.rs │ │ ├── docs.rs │ │ ├── error.rs │ │ ├── ir.rs │ │ ├── ir │ │ │ ├── compiler.rs │ │ │ ├── eval.rs │ │ │ ├── interpreter.rs │ │ │ └── scopes.rs │ │ ├── location.rs │ │ ├── meta.rs │ │ ├── meta_info.rs │ │ ├── mod.rs │ │ ├── named.rs │ │ ├── names.rs │ │ ├── names │ │ │ └── tests.rs │ │ ├── options.rs │ │ ├── pool.rs │ │ ├── prelude.rs │ │ ├── source_loader.rs │ │ ├── unit_builder.rs │ │ ├── v1 │ │ │ ├── assemble.rs │ │ │ ├── breaks.rs │ │ │ ├── display_named.rs │ │ │ ├── linear.rs │ │ │ ├── mod.rs │ │ │ ├── needs.rs │ │ │ ├── scopes.rs │ │ │ ├── slab.rs │ │ │ ├── slots.rs │ │ │ └── slots │ │ │ │ └── tests.rs │ │ ├── visibility.rs │ │ └── with_span.rs │ ├── diagnostics │ │ ├── emit.rs │ │ ├── fatal.rs │ │ ├── mod.rs │ │ ├── runtime_warning.rs │ │ └── warning.rs │ ├── doc │ │ ├── artifacts.rs │ │ ├── build.rs │ │ ├── build │ │ │ ├── js.rs │ │ │ └── type_.rs │ │ ├── context.rs │ │ ├── markdown.rs │ │ ├── mod.rs │ │ ├── static │ │ │ ├── fonts │ │ │ │ ├── FiraSans-Medium.woff2 │ │ │ │ ├── FiraSans-Regular.woff2 │ │ │ │ ├── NanumBarunGothic-Regular.woff2 │ │ │ │ ├── SourceCodePro-It.ttf.woff2 │ │ │ │ ├── SourceCodePro-Regular.woff2 │ │ │ │ ├── SourceCodePro-Semibold.woff2 │ │ │ │ ├── SourceSerif4-Bold.woff2 │ │ │ │ └── SourceSerif4-Regular.woff2 │ │ │ ├── function.html.hbs │ │ │ ├── index.html.hbs │ │ │ ├── layout.html.hbs │ │ │ ├── macro.html.hbs │ │ │ ├── module.html.hbs │ │ │ ├── runedoc.css.hbs │ │ │ ├── search.js │ │ │ └── type.html.hbs │ │ ├── templating.rs │ │ └── visitor.rs │ ├── exported_macros.rs │ ├── fmt │ │ ├── format.rs │ │ ├── mod.rs │ │ ├── output.rs │ │ └── tests │ │ │ ├── macros.rs │ │ │ └── mod.rs │ ├── function │ │ ├── macros.rs │ │ └── mod.rs │ ├── function_meta.rs │ ├── grammar │ │ ├── classify.rs │ │ ├── flavor.rs │ │ ├── grammar.rs │ │ ├── mod.rs │ │ ├── parser.rs │ │ └── tree.rs │ ├── hash.rs │ ├── hashbrown │ │ ├── mod.rs │ │ └── table.rs │ ├── hir │ │ ├── arena.rs │ │ ├── arena │ │ │ └── tests.rs │ │ ├── ctxt.rs │ │ ├── hir.rs │ │ ├── interpreter.rs │ │ ├── lowering.rs │ │ ├── lowering2.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ └── scopes.rs │ ├── indexing │ │ ├── index.rs │ │ ├── index2.rs │ │ ├── indexer.rs │ │ ├── items.rs │ │ ├── mod.rs │ │ └── scopes.rs │ ├── internal_macros.rs │ ├── item.rs │ ├── languageserver │ │ ├── completion.rs │ │ ├── connection.rs │ │ ├── envelope.rs │ │ ├── fs.rs │ │ ├── mod.rs │ │ ├── state.rs │ │ ├── tests.rs │ │ └── url.rs │ ├── lib.rs │ ├── location.rs │ ├── macros │ │ ├── format_args.rs │ │ ├── into_lit.rs │ │ ├── macro_compiler.rs │ │ ├── macro_context.rs │ │ ├── mod.rs │ │ ├── quote_fn.rs │ │ ├── storage.rs │ │ └── token_stream.rs │ ├── module │ │ ├── enum_mut.rs │ │ ├── install_with.rs │ │ ├── item_fn_mut.rs │ │ ├── item_mut.rs │ │ ├── mod.rs │ │ ├── module.rs │ │ ├── module_constant_builder.rs │ │ ├── module_function_builder.rs │ │ ├── module_meta.rs │ │ ├── module_raw_function_builder.rs │ │ ├── trait_mut.rs │ │ ├── type_mut.rs │ │ └── variant_mut.rs │ ├── modules │ │ ├── any.rs │ │ ├── bytes.rs │ │ ├── capture_io.rs │ │ ├── char.rs │ │ ├── clone.rs │ │ ├── cmp.rs │ │ ├── collections │ │ │ ├── hash_map.rs │ │ │ ├── hash_set.rs │ │ │ ├── mod.rs │ │ │ └── vec_deque.rs │ │ ├── core.rs │ │ ├── disable_io.rs │ │ ├── f64.rs │ │ ├── fmt.rs │ │ ├── future.rs │ │ ├── hash.rs │ │ ├── i64.rs │ │ ├── inner_macros.rs │ │ ├── io.rs │ │ ├── iter.rs │ │ ├── macros.rs │ │ ├── macros │ │ │ └── builtin.rs │ │ ├── mem.rs │ │ ├── mod.rs │ │ ├── num.rs │ │ ├── object.rs │ │ ├── ops.rs │ │ ├── ops │ │ │ └── generator.rs │ │ ├── option.rs │ │ ├── result.rs │ │ ├── slice.rs │ │ ├── stream.rs │ │ ├── string.rs │ │ ├── test.rs │ │ ├── tuple.rs │ │ ├── u64.rs │ │ └── vec.rs │ ├── musli.rs │ ├── no_std │ │ └── mod.rs │ ├── params.rs │ ├── parse │ │ ├── expectation.rs │ │ ├── id.rs │ │ ├── lexer.rs │ │ ├── lexer │ │ │ └── tests.rs │ │ ├── mod.rs │ │ ├── parse.rs │ │ ├── parser.rs │ │ ├── peek.rs │ │ ├── resolve.rs │ │ └── traits.rs │ ├── query │ │ ├── mod.rs │ │ └── query.rs │ ├── runtime │ │ ├── access.rs │ │ ├── any_obj.rs │ │ ├── any_obj_vtable.rs │ │ ├── args.rs │ │ ├── awaited.rs │ │ ├── borrow_mut.rs │ │ ├── borrow_ref.rs │ │ ├── budget.rs │ │ ├── budget │ │ │ ├── no_std.rs │ │ │ └── std.rs │ │ ├── bytes.rs │ │ ├── call.rs │ │ ├── const_value.rs │ │ ├── const_value │ │ │ └── macros.rs │ │ ├── control_flow.rs │ │ ├── debug.rs │ │ ├── dynamic.rs │ │ ├── env.rs │ │ ├── env │ │ │ ├── no_std.rs │ │ │ └── std.rs │ │ ├── fmt.rs │ │ ├── format.rs │ │ ├── from_value.rs │ │ ├── function.rs │ │ ├── future.rs │ │ ├── generator.rs │ │ ├── generator_state.rs │ │ ├── guarded_args.rs │ │ ├── hasher.rs │ │ ├── inst.rs │ │ ├── iterator.rs │ │ ├── label.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── object.rs │ │ ├── panic.rs │ │ ├── protocol.rs │ │ ├── protocol_caller.rs │ │ ├── range.rs │ │ ├── range_from.rs │ │ ├── range_full.rs │ │ ├── range_inclusive.rs │ │ ├── range_to.rs │ │ ├── range_to_inclusive.rs │ │ ├── ref.rs │ │ ├── runtime_context.rs │ │ ├── select.rs │ │ ├── shared.rs │ │ ├── slice.rs │ │ ├── slice │ │ │ └── iter.rs │ │ ├── stack.rs │ │ ├── static_string.rs │ │ ├── steps_between.rs │ │ ├── stream.rs │ │ ├── tests.rs │ │ ├── to_value.rs │ │ ├── tuple.rs │ │ ├── type.rs │ │ ├── type_info.rs │ │ ├── type_of.rs │ │ ├── unit.rs │ │ ├── unit │ │ │ ├── byte_code.rs │ │ │ └── storage.rs │ │ ├── value.rs │ │ ├── value │ │ │ ├── any_sequence.rs │ │ │ ├── data.rs │ │ │ ├── inline.rs │ │ │ ├── macros.rs │ │ │ ├── rtti.rs │ │ │ ├── serde.rs │ │ │ └── tests.rs │ │ ├── vec.rs │ │ ├── vec_tuple.rs │ │ ├── vm.rs │ │ ├── vm │ │ │ └── ops.rs │ │ ├── vm_call.rs │ │ ├── vm_diagnostics.rs │ │ ├── vm_error.rs │ │ ├── vm_execution.rs │ │ └── vm_halt.rs │ ├── serde.rs │ ├── shared │ │ ├── assert_send.rs │ │ ├── caller.rs │ │ ├── consts.rs │ │ ├── fixed_vec.rs │ │ ├── gen.rs │ │ └── mod.rs │ ├── source.rs │ ├── sources.rs │ ├── span.rs │ ├── support.rs │ ├── tests.rs │ ├── tests │ │ ├── attribute.rs │ │ ├── binary.rs │ │ ├── bug_326.rs │ │ ├── bug_344.rs │ │ ├── bug_417.rs │ │ ├── bug_422.rs │ │ ├── bug_428.rs │ │ ├── bug_454.rs │ │ ├── bug_700.rs │ │ ├── bug_905.rs │ │ ├── bugfixes.rs │ │ ├── builtin_macros.rs │ │ ├── capture.rs │ │ ├── comments.rs │ │ ├── compiler_docs.rs │ │ ├── compiler_expr_assign.rs │ │ ├── compiler_fn.rs │ │ ├── compiler_general.rs │ │ ├── compiler_literals.rs │ │ ├── compiler_paths.rs │ │ ├── compiler_patterns.rs │ │ ├── compiler_use.rs │ │ ├── compiler_visibility.rs │ │ ├── compiler_warnings.rs │ │ ├── continue_.rs │ │ ├── core_macros.rs │ │ ├── custom_macros.rs │ │ ├── debug_fmt.rs │ │ ├── deprecation.rs │ │ ├── derive_constructor.rs │ │ ├── destructuring.rs │ │ ├── esoteric_impls.rs │ │ ├── external_constructor.rs │ │ ├── external_generic.rs │ │ ├── external_match.rs │ │ ├── external_ops.rs │ │ ├── function_guardedargs.rs │ │ ├── getter_setter.rs │ │ ├── iterator.rs │ │ ├── macros.rs │ │ ├── macros │ │ │ └── stringy_math.rs │ │ ├── moved.rs │ │ ├── option.rs │ │ ├── patterns.rs │ │ ├── quote.rs │ │ ├── range.rs │ │ ├── reference_error.rs │ │ ├── rename_type.rs │ │ ├── result.rs │ │ ├── static_typing.rs │ │ ├── tuple.rs │ │ ├── type_name_native.rs │ │ ├── unit_constants.rs │ │ ├── unreachable.rs │ │ ├── vm_arithmetic.rs │ │ ├── vm_assign_exprs.rs │ │ ├── vm_async_block.rs │ │ ├── vm_blocks.rs │ │ ├── vm_closures.rs │ │ ├── vm_const_exprs.rs │ │ ├── vm_early_termination.rs │ │ ├── vm_function.rs │ │ ├── vm_function_pointers.rs │ │ ├── vm_general.rs │ │ ├── vm_literals.rs │ │ ├── vm_not_used.rs │ │ ├── vm_result.rs │ │ ├── vm_test_from_value_derive.rs │ │ ├── vm_test_imports.rs │ │ ├── vm_test_instance_fns.rs │ │ ├── vm_test_linked_list.rs │ │ ├── vm_test_mod.rs │ │ ├── vm_try.rs │ │ └── wildcard_imports.rs │ ├── worker │ │ ├── import.rs │ │ ├── mod.rs │ │ ├── task.rs │ │ └── wildcard_import.rs │ └── workspace │ │ ├── build.rs │ │ ├── diagnostics.rs │ │ ├── emit.rs │ │ ├── error.rs │ │ ├── glob.rs │ │ ├── glob │ │ └── tests.rs │ │ ├── manifest.rs │ │ ├── mod.rs │ │ ├── source_loader.rs │ │ └── spanned_value.rs │ └── tests │ ├── assign.rn │ ├── basics.rn │ ├── blocks.rn │ ├── bug_830.rn │ ├── bug_838.rn │ ├── char.rn │ ├── closures.rn │ ├── const.rn │ ├── continue.rn │ ├── derive_from_value.rs │ ├── diverging.rn │ ├── esoteric_impls.rn │ ├── float.rn │ ├── flow_control.rn │ ├── for_loops.rn │ ├── function_pointers.rn │ ├── general.rn │ ├── generators.rn │ ├── generic_fns.rn │ ├── ifs.rn │ ├── imports.rn │ ├── instance.rn │ ├── int_ops.rn │ ├── iter.rn │ ├── lazy_and_or.rn │ ├── linked_list.rn │ ├── loops.rn │ ├── matching.rn │ ├── modules_inline.rn │ ├── modules_vis.rn │ ├── non_ascii_idents.rn │ ├── operator_is.rn │ ├── option.rn │ ├── pat.rn │ ├── range.rn │ ├── reordering.rn │ ├── result.rn │ ├── select.rn │ ├── streams.rn │ ├── try.rn │ ├── tuples.rn │ ├── type_name_of_val.rn │ ├── typed_tuple.rn │ ├── types.rn │ ├── ui.rs │ ├── ui │ ├── install_with_compat.rs │ └── install_with_compat.stderr │ ├── use.rn │ └── variants.rn ├── editors └── code │ ├── .eslintrc.json │ ├── .gitignore │ ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json │ ├── .vscodeignore │ ├── .yarnrc │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── LICENSE.md │ ├── README.md │ ├── assets │ ├── icon.png │ └── logo.png │ ├── language-configuration.json │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── client.ts │ ├── config.ts │ ├── ctx.ts │ ├── extension.ts │ ├── net.ts │ ├── persistent_state.ts │ ├── test │ │ ├── runTest.ts │ │ └── suite │ │ │ ├── extension.test.ts │ │ │ └── index.ts │ └── util.ts │ ├── syntaxes │ └── rune.tmLanguage.json │ ├── tsconfig.json │ ├── webpack.config.js │ └── yarn.lock ├── examples ├── Cargo.toml ├── README.md ├── Rune.toml ├── ace │ ├── .gitignore │ ├── README.md │ └── index.html ├── examples │ ├── checked_add_assign.rs │ ├── concat_idents.rs │ ├── custom_instance_fn.rs │ ├── custom_mul.rs │ ├── external_enum.rs │ ├── external_struct.rs │ ├── function_hash.rs │ ├── hot_reloading.rs │ ├── hot_reloading │ │ └── path_reloader.rs │ ├── lookup_function.rs │ ├── minimal.rs │ ├── module.rn │ ├── native_function.rs │ ├── object.rs │ ├── parsing_in_macro.rs │ ├── proxy.rs │ ├── references.rs │ ├── rune_function.rs │ ├── rune_function_macro.rs │ ├── simple_external.rs │ ├── test.rn │ ├── tokio_spawn.rs │ ├── tuple.rs │ ├── vec_args.rs │ ├── vec_tuple.rs │ └── vector.rs └── scripts │ └── change_me.rn ├── no-std ├── .gitignore ├── Cargo.toml └── examples │ └── minimal.rs ├── scripts ├── arrays.rn ├── async.rn ├── book │ ├── async │ │ ├── async_blocks.rn │ │ ├── async_closure.rn │ │ ├── async_http.rn │ │ ├── async_http_concurrent.rn │ │ └── async_http_timeout.rn │ ├── closures │ │ ├── basic_closure.rn │ │ ├── closure_move.rn.fail │ │ └── function_pointers.rn │ ├── compiler_guide │ │ ├── closures.rn │ │ └── dead_code.rn │ ├── control_flow │ │ ├── conditional.rn │ │ ├── conditional_else.rn │ │ ├── conditional_else_ifs.rn │ │ ├── first_match.rn │ │ └── numbers_game.rn │ ├── dynamic_types │ │ └── greeting.rn │ ├── enums │ │ └── count_numbers.rn │ ├── functions │ │ ├── main_function.rn │ │ └── return_value.rn │ ├── generators │ │ ├── bootup.rn │ │ ├── error.rn │ │ ├── fib_generator.rn │ │ ├── send_values.rn │ │ └── states.rn │ ├── getting_started │ │ ├── dbg.rn │ │ └── hello_world.rn │ ├── instance_functions │ │ └── missing_instance_fn.rn │ ├── items_imports │ │ ├── bar.rn │ │ ├── example_import.rn │ │ ├── foo │ │ │ └── mod.rn │ │ ├── inline_modules.rn │ │ ├── item_keywords.rn │ │ ├── missing_item.rn.fail │ │ └── modules.rn │ ├── loops │ │ ├── loop_break.rn │ │ ├── loop_forever.rn │ │ └── while_loop.rn │ ├── objects │ │ ├── json.rn │ │ └── objects.rn │ ├── pattern_matching │ │ ├── big_match.rn │ │ ├── bind.rn │ │ ├── fast_cars.rn │ │ ├── ignore.rn │ │ └── rest_pattern.rn │ ├── primitives │ │ ├── copy.rn │ │ └── primitives.rn │ ├── streams │ │ └── basic_stream.rn │ ├── structs │ │ ├── struct_matching.rn │ │ └── user_database.rn │ ├── template_literals │ │ ├── basic_template.rn │ │ └── not_a_template.rn │ ├── the_stack │ │ ├── add.rn │ │ └── call_and_add.rn │ ├── try_operator │ │ └── basic_try.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 │ ├── variables │ │ ├── is_readable.rn │ │ ├── shared_ownership.rn │ │ ├── take_argument.rn │ │ └── variables.rn │ └── vectors │ │ ├── vectors.rn │ │ └── vectors_rev.rn ├── broken.rn ├── bytes.rn ├── compile-fail │ ├── attributes.rn.fail │ └── experimental_macro_error.rn.fail ├── constant_expr.rn ├── controls.rn ├── doc.rn ├── fib.rn ├── generator_as_iter.rn ├── generator_resume.rn ├── hello_world.rn ├── http.rn ├── json.rn ├── linked_list.rn ├── not_used.rn ├── numbers.rn ├── objects.rn ├── primes.rn ├── py │ └── linked_list.py ├── rand.rn ├── reverse_iterator.rn ├── signal.rn └── strings.rn ├── site ├── .gitignore ├── README.md ├── config.toml ├── content │ ├── _index.md │ ├── play.md │ ├── posts │ │ ├── 2020-09-18-hello-internet.md │ │ ├── 2020-10-19-common-miscompilation.md │ │ ├── 2020-10-19-tmir1.md │ │ ├── 2020-12-07-faster-tests.md │ │ ├── 2023-10-10-is-alphabetic-doc.png │ │ ├── 2023-10-10-my-project-cli.png │ │ ├── 2023-10-10-rune-0.13.0.md │ │ └── _index.md │ └── rune.md ├── sass │ ├── _macros.scss │ ├── _shortcodes.scss │ ├── _vars.scss │ └── style.scss ├── static │ ├── ace │ │ └── mode-rune.js │ ├── img │ │ └── logo.png │ └── index.js ├── syntaxes │ ├── rune.sublime-syntax │ └── rune.tmLanguage ├── templates │ ├── base.html │ ├── index.html │ ├── macros.html │ ├── page.html │ ├── play.html │ ├── post.html │ ├── posts.html │ └── shortcodes │ │ ├── quote.html │ │ ├── rune.html │ │ ├── vm.html │ │ └── yt.html └── theme.toml └── tools ├── builder ├── .gitignore ├── Cargo.toml ├── README.md └── src │ └── main.rs ├── function_traits_permute.py ├── generate ├── .gitignore ├── Cargo.toml ├── README.md └── src │ └── main.rs └── site ├── .gitignore ├── Cargo.toml ├── README.md └── src └── main.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | **/generated.rs linguist-generated=true 2 | **/generated.rs -diff -merge 3 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 John-John Tedro 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Rune.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "benches", 4 | "examples", 5 | "crates/rune", 6 | ] 7 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/assets/icon.xcf -------------------------------------------------------------------------------- /assets/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/assets/logo.xcf -------------------------------------------------------------------------------- /assets/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/assets/social.png -------------------------------------------------------------------------------- /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.4.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /benches/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune-benches" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /book/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /book/src/streams.md: -------------------------------------------------------------------------------- 1 | # Streams 2 | 3 | Streams are the asynchronous version of [Generators](./7_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 | -------------------------------------------------------------------------------- /book/src/string_literals.md: -------------------------------------------------------------------------------- 1 | You're probably looking for the section about [Template literals](template_literals.md). 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.82" 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/.gitignore: -------------------------------------------------------------------------------- 1 | /patches/ 2 | -------------------------------------------------------------------------------- /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-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-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-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 | #[inline] 11 | fn try_write_str(&mut self, s: &str) -> Result<(), Error> { 12 | self.try_extend_from_slice(s.as_bytes()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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: Sized { 6 | /// Try to join the given value in the given allocator. 7 | fn try_join_in(iter: I, sep: S, alloc: A) -> Result 8 | where 9 | I: IntoIterator; 10 | } 11 | -------------------------------------------------------------------------------- /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-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: 'a> Iterator for TryCloned 22 | where 23 | I: Iterator, 24 | T: 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 | fn size_hint(&self) -> (usize, Option) { 34 | self.it.size_hint() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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-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-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-alloc/src/option/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::ext::OptionExt; 2 | pub(crate) mod ext; 3 | -------------------------------------------------------------------------------- /crates/rune-alloc/src/serde/mod.rs: -------------------------------------------------------------------------------- 1 | mod de; 2 | mod ser; 3 | -------------------------------------------------------------------------------- /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-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-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-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 | -------------------------------------------------------------------------------- /crates/rune-alloc/third-party/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /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-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.82" 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"] } 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-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-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-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-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.82" 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"] } 24 | rune-modules = { version = "0.14.0", path = "../rune-modules", features = ["full"] } 25 | 26 | [build-dependencies] 27 | anyhow = "1.0.71" 28 | -------------------------------------------------------------------------------- /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-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.82" 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-modules/src/rand/error.rs: -------------------------------------------------------------------------------- 1 | use rune::alloc::fmt::TryWrite; 2 | use rune::runtime::{Formatter, VmResult}; 3 | use rune::{vm_write, Any}; 4 | 5 | /// An error returned by methods in the `rand` module. 6 | #[derive(Debug, Any)] 7 | #[rune(item = ::rand)] 8 | pub(super) struct Error { 9 | pub(super) inner: getrandom::Error, 10 | } 11 | 12 | impl From for Error { 13 | #[inline] 14 | fn from(inner: getrandom::Error) -> Self { 15 | Self { inner } 16 | } 17 | } 18 | 19 | impl Error { 20 | /// Write a display representation the error. 21 | #[rune::function(instance, protocol = DISPLAY_FMT)] 22 | fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { 23 | vm_write!(f, "{}", self.inner) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crates/rune-modules/src/rand/os_error.rs: -------------------------------------------------------------------------------- 1 | use rune::alloc::fmt::TryWrite; 2 | use rune::runtime::{Formatter, VmResult}; 3 | use rune::{vm_write, Any}; 4 | 5 | /// An os error returned by methods in the `rand` module. 6 | #[derive(Debug, Any)] 7 | #[rune(item = ::rand)] 8 | pub(super) struct OsError { 9 | pub(super) inner: rand::rand_core::OsError, 10 | } 11 | 12 | impl From for OsError { 13 | #[inline] 14 | fn from(inner: rand::rand_core::OsError) -> Self { 15 | Self { inner } 16 | } 17 | } 18 | 19 | impl OsError { 20 | /// Write a display representation the error. 21 | #[rune::function(instance, protocol = DISPLAY_FMT)] 22 | fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { 23 | vm_write!(f, "{}", self.inner) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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.82" 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-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.82" 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-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /out -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-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 | }; -------------------------------------------------------------------------------- /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/.gitignore: -------------------------------------------------------------------------------- 1 | /wip/ 2 | -------------------------------------------------------------------------------- /crates/rune/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rune" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | #[cfg(debug_assertions)] 11 | use rust_alloc::boxed::Box; 12 | #[cfg(debug_assertions)] 13 | use rust_alloc::string::String; 14 | 15 | use rust_embed::RustEmbed; 16 | 17 | #[derive(RustEmbed)] 18 | #[folder = "src/ace/static"] 19 | pub(super) struct Assets; 20 | } 21 | 22 | pub(crate) fn theme(artifacts: &mut Artifacts) -> Result<()> { 23 | for name in ["rune-mode.js", "rune-highlight-rules.js"] { 24 | artifacts.asset(false, name, || { 25 | let file = embed::Assets::get(name).with_context(|| anyhow!("missing {name}"))?; 26 | Ok(Cow::try_from(file.data)?) 27 | })?; 28 | } 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /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/src/ace/static/rune-mode.js: -------------------------------------------------------------------------------- 1 | ace.define('ace/mode/rune', 2 | ["require", "exports", "module", "ace/lib/oop", "ace/mode/folding/cstyle", "ace/mode/text", "ace/mode/rune-highlight-rules"], 3 | function (require, exports, module) { 4 | "use strict"; 5 | 6 | const TextMode = require("ace/mode/text").Mode; 7 | const FoldMode = require("ace/mode/folding/cstyle").FoldMode; 8 | const RuneHighlightRules = require("ace/mode/rune-highlight-rules").RuneHighlightRules; 9 | const oop = require("ace/lib/oop"); 10 | 11 | const Mode = function () { 12 | this.HighlightRules = RuneHighlightRules; 13 | this.foldingRules = new FoldMode(); 14 | this.$behaviour = this.$defaultBehaviour; 15 | }; 16 | 17 | oop.inherits(Mode, TextMode); 18 | 19 | (function () { 20 | this.lineCommentStart = "//"; 21 | this.blockComment = { start: "/*", end: "*/", nestable: true }; 22 | this.$quotes = { '"': '"' }; 23 | this.$id = "ace/mode/rune"; 24 | }).call(Mode.prototype); 25 | 26 | exports.Mode = Mode; 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /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/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/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_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 | -------------------------------------------------------------------------------- /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/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/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/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/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_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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/cli/languageserver.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | 3 | use crate::{Context, Options}; 4 | 5 | pub(super) async fn run(context: Context) -> Result<()> { 6 | let options = Options::from_default_env()?; 7 | crate::languageserver::run(context, options).await?; 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /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/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/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/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/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/src/doc/static/fonts/FiraSans-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/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/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/FiraSans-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/NanumBarunGothic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/NanumBarunGothic-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceCodePro-It.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/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/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/SourceCodePro-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceCodePro-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/SourceCodePro-Semibold.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceSerif4-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/SourceSerif4-Bold.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/fonts/SourceSerif4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/crates/rune/src/doc/static/fonts/SourceSerif4-Regular.woff2 -------------------------------------------------------------------------------- /crates/rune/src/doc/static/function.html.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout}} 2 | 3 |
4 |

Function {{literal module}}::{{name}}

Overview
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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/src/hashbrown/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use self::table::{IterRef, KeysRef, Table, ValuesRef}; 2 | mod table; 3 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /crates/rune/src/languageserver/fs.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::path::Path; 3 | 4 | /// Test if the given path is a file. 5 | pub(super) async fn is_file

(path: P) -> io::Result 6 | where 7 | P: AsRef, 8 | { 9 | match tokio::fs::metadata(path).await { 10 | Ok(m) => Ok(m.is_file()), 11 | Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(false), 12 | Err(e) => Err(e), 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /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/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/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/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/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/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; 8 | use crate::alloc::string::TryToString; 9 | use crate::runtime::{VmErrorKind, VmResult}; 10 | use crate::{ContextError, Module}; 11 | 12 | /// Signed integers. 13 | /// 14 | /// This provides methods for computing over and parsing 64-bit signed integers. 15 | #[rune::module(::std::i64)] 16 | pub fn module() -> Result { 17 | let mut m = Module::from_meta(self::module__meta)?; 18 | signed!(m, i64); 19 | Ok(m) 20 | } 21 | 22 | signed_fns!(i64); 23 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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; 8 | use crate::alloc::string::TryToString; 9 | use crate::runtime::{VmErrorKind, VmResult}; 10 | use crate::{ContextError, Module}; 11 | 12 | /// Unsigned integers. 13 | /// 14 | /// This provides methods for computing over and parsing 64-bit unsigned integers. 15 | #[rune::module(::std::u64)] 16 | pub fn module() -> Result { 17 | let mut m = Module::from_meta(self::module__meta)?; 18 | unsigned!(m, u64); 19 | Ok(m) 20 | } 21 | 22 | unsigned_fns!(u64); 23 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/awaited.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::{Future, Output, Select, Vm, VmResult}; 2 | use crate::vm_try; 3 | 4 | /// A stored await task. 5 | #[derive(Debug)] 6 | pub(crate) enum Awaited { 7 | /// A future to be awaited. 8 | Future(Future, Output), 9 | /// A select to be awaited. 10 | Select(Select, Output), 11 | } 12 | 13 | impl Awaited { 14 | /// Wait for the given awaited into the specified virtual machine. 15 | pub(crate) async fn into_vm(self, vm: &mut Vm) -> VmResult<()> { 16 | match self { 17 | Self::Future(future, out) => { 18 | let value = vm_try!(future.await.with_vm(vm)); 19 | vm_try!(out.store(vm.stack_mut(), value)); 20 | } 21 | Self::Select(select, value_addr) => { 22 | let (ip, value) = vm_try!(select.await.with_vm(vm)); 23 | vm.set_ip(ip); 24 | vm_try!(value_addr.store(vm.stack_mut(), || value)); 25 | } 26 | } 27 | 28 | VmResult::Ok(()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/runtime/hasher.rs: -------------------------------------------------------------------------------- 1 | use core::hash::{BuildHasher, Hasher as _}; 2 | 3 | use rune_alloc::hash_map; 4 | 5 | use crate as rune; 6 | use crate::Any; 7 | 8 | /// The default hasher used in Rune. 9 | #[derive(Any)] 10 | #[rune(item = ::std::hash)] 11 | pub struct Hasher { 12 | hasher: hash_map::Hasher, 13 | } 14 | 15 | impl Hasher { 16 | /// Construct a new empty hasher. 17 | pub(crate) fn new_with(build_hasher: &S) -> Self 18 | where 19 | S: BuildHasher, 20 | { 21 | Self { 22 | hasher: build_hasher.build_hasher(), 23 | } 24 | } 25 | 26 | /// Hash a string. 27 | pub(crate) fn write_str(&mut self, string: &str) { 28 | self.hasher.write(string.as_bytes()); 29 | } 30 | 31 | /// Construct a hash. 32 | pub fn finish(&self) -> u64 { 33 | self.hasher.finish() 34 | } 35 | } 36 | 37 | impl core::hash::Hasher for Hasher { 38 | #[inline] 39 | fn finish(&self) -> u64 { 40 | self.hasher.finish() 41 | } 42 | 43 | #[inline] 44 | fn write(&mut self, bytes: &[u8]) { 45 | self.hasher.write(bytes); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crates/rune/src/runtime/iterator.rs: -------------------------------------------------------------------------------- 1 | use crate::alloc; 2 | use crate::compile::meta; 3 | 4 | use super::{FromValue, MaybeTypeOf, RuntimeError, Value, VmResult}; 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) -> VmResult<(usize, Option)> { 19 | self.iter.protocol_size_hint() 20 | } 21 | 22 | #[inline] 23 | pub(crate) fn next(&mut self) -> VmResult> { 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().into_result().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/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/src/runtime/select.rs: -------------------------------------------------------------------------------- 1 | use core::future; 2 | use core::pin::Pin; 3 | use core::task::{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, VmResult}; 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 = VmResult<(usize, Value)>; 26 | 27 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 28 | let poll = Pin::new(&mut self.futures).poll_next(cx); 29 | 30 | let poll = match poll { 31 | Poll::Ready(poll) => poll.expect("inner stream should never end"), 32 | Poll::Pending => return Poll::Pending, 33 | }; 34 | 35 | Poll::Ready(poll) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/src/tests/reference_error.rs: -------------------------------------------------------------------------------- 1 | prelude!(); 2 | 3 | use std::sync::Arc; 4 | 5 | #[test] 6 | fn test_reference_error() -> Result<()> { 7 | #[derive(Debug, Default, Any)] 8 | struct Foo { 9 | value: i64, 10 | } 11 | 12 | // NB: Calling this should error, since it's a mutable reference. 13 | fn take_it(_: Ref) -> VmResult<()> { 14 | VmResult::Ok(()) 15 | } 16 | 17 | let mut module = Module::new(); 18 | module.function("take_it", take_it).build()?; 19 | 20 | let mut context = Context::new(); 21 | context.install(module)?; 22 | 23 | let mut sources = sources! { 24 | entry => { 25 | fn main(number) { take_it(number) } 26 | } 27 | }; 28 | 29 | let unit = prepare(&mut sources).with_context(&context).build()?; 30 | 31 | let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); 32 | 33 | let mut foo = Foo::default(); 34 | assert_eq!(foo.value, 0); 35 | 36 | // This should error, because we're trying to acquire an `Ref` out of a 37 | // passed in reference. 38 | assert!(vm.call(["main"], (&mut foo,)).is_err()); 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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::{Found, FoundKind, FoundPackage, Manifest, Package, WorkspaceFilter}; 27 | 28 | mod diagnostics; 29 | pub use self::diagnostics::{Diagnostic, Diagnostics, FatalDiagnostic}; 30 | 31 | mod source_loader; 32 | pub use self::source_loader::{FileSourceLoader, SourceLoader}; 33 | -------------------------------------------------------------------------------- /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/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/tests/bug_830.rn: -------------------------------------------------------------------------------- 1 | // This tests an issue where the temporary value inside of the `&&` operator 2 | // overwrites the left hand side slot. 3 | // https://github.com/rune-rs/rune/issues/830 4 | 5 | #[test] 6 | fn if_stmt() { 7 | let value = true; 8 | 9 | if value && false { 10 | panic!("should not be reached"); 11 | } 12 | 13 | assert!(value); 14 | } 15 | 16 | #[test] 17 | fn else_if_stmt() { 18 | let value = true; 19 | 20 | if false { 21 | panic!("should not be reached"); 22 | } else if value && false { 23 | panic!("should not be reached"); 24 | } 25 | 26 | assert!(value); 27 | } 28 | 29 | #[test] 30 | fn while_stmt() { 31 | let value = true; 32 | 33 | while value && false { 34 | panic!("should not be reached"); 35 | } 36 | 37 | assert!(value); 38 | } 39 | 40 | #[test] 41 | fn match_stmt() { 42 | let value = true; 43 | 44 | let value2 = match true { 45 | false => false, 46 | _ if value && false => panic!("should not be reached"), 47 | true => true, 48 | }; 49 | 50 | assert!(value); 51 | assert!(value2); 52 | } 53 | -------------------------------------------------------------------------------- /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/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/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/diverging.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn diverging_if() { 3 | fn inner() { 4 | if return true { 5 | } 6 | 7 | false 8 | } 9 | 10 | assert!(inner()); 11 | } 12 | 13 | #[test] 14 | fn diverging_condition_while() { 15 | fn inner() { 16 | while return true { 17 | } 18 | 19 | false 20 | } 21 | 22 | assert!(inner()); 23 | } 24 | 25 | #[test] 26 | fn diverging_condition_match() { 27 | fn inner() { 28 | match true { 29 | false => false, 30 | _ if return true => false, 31 | true => false, 32 | } 33 | } 34 | 35 | assert!(inner()); 36 | } 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /crates/rune/tests/flow_control.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 | #[test] 58 | fn test_flow_control() { 59 | assert_eq!(test(0), 0); 60 | assert_eq!(test2(1), 1); 61 | assert_eq!(test3(2), 2); 62 | assert_eq!(from_loop(), 4); 63 | assert_eq!(returns_unit(1), ()); 64 | assert_eq!(returns_string(), "this is a string"); 65 | } 66 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /crates/rune/tests/ifs.rn: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn test_if_else() { 3 | let number = 3; 4 | 5 | let out = 0; 6 | 7 | if number < 5 { 8 | out = 1; 9 | } else if number == 5 { 10 | out = 2; 11 | } else { 12 | out = 3; 13 | } 14 | 15 | assert_eq!(out, 1); 16 | } 17 | 18 | #[test] 19 | fn test_control_flow() { 20 | fn foo(n) { 21 | if n < 1 { 22 | return "less than one"; 23 | } 24 | 25 | "something else" 26 | } 27 | 28 | assert_eq!(foo(0), "less than one"); 29 | assert_eq!(foo(10), "something else"); 30 | } 31 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /editors/code/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | server 4 | node_modules 5 | .vscode-test/ 6 | *.vsix 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /editors/code/.yarnrc: -------------------------------------------------------------------------------- 1 | --ignore-engines true -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /editors/code/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/editors/code/assets/icon.png -------------------------------------------------------------------------------- /editors/code/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/editors/code/assets/logo.png -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 = "7.0.0" 17 | anyhow = "1.0.82" 18 | pin-project = "1.1.5" 19 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # rune examples 2 | 3 | See: 4 | 5 | * [examples] - wide range of rust code examples. 6 | * [ace] - ace editor integration. -------------------------------------------------------------------------------- /examples/Rune.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /examples/ace/.gitignore: -------------------------------------------------------------------------------- 1 | rune-autocomplete.js 2 | rune-mode.js 3 | rune-highlight-rules.js 4 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/examples/lookup_function.rs: -------------------------------------------------------------------------------- 1 | use rune::{Context, Vm}; 2 | 3 | use std::sync::Arc; 4 | 5 | fn main() -> rune::support::Result<()> { 6 | let context = Context::with_default_modules()?; 7 | let context = Arc::new(context.runtime()?); 8 | 9 | let mut sources = rune::sources! { 10 | entry => { 11 | pub fn max(a, b) { 12 | if a > b { 13 | a 14 | } else { 15 | b 16 | } 17 | } 18 | } 19 | }; 20 | 21 | let unit = rune::prepare(&mut sources).build()?; 22 | let unit = Arc::new(unit); 23 | 24 | let vm = Vm::new(context, unit); 25 | 26 | // Looking up an item from the source. 27 | let dynamic_max = vm.lookup_function(["max"])?; 28 | 29 | let value = dynamic_max.call::((10, 20)).into_result()?; 30 | assert_eq!(value, 20); 31 | 32 | let item = rune::item!(::std::i64::max); 33 | let max = vm.lookup_function(item)?; 34 | 35 | let value = max.call::((10, 20)).into_result()?; 36 | assert_eq!(value, 20); 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /examples/examples/minimal.rs: -------------------------------------------------------------------------------- 1 | use rune::termcolor::{ColorChoice, StandardStream}; 2 | use rune::{Diagnostics, Vm}; 3 | 4 | use std::sync::Arc; 5 | 6 | fn main() -> rune::support::Result<()> { 7 | let context = rune_modules::default_context()?; 8 | 9 | let mut sources = rune::sources!( 10 | entry => { 11 | pub fn main(number) { 12 | number + 10 13 | } 14 | } 15 | ); 16 | 17 | let mut diagnostics = Diagnostics::new(); 18 | 19 | let result = rune::prepare(&mut sources) 20 | .with_context(&context) 21 | .with_diagnostics(&mut diagnostics) 22 | .build(); 23 | 24 | if !diagnostics.is_empty() { 25 | let mut writer = StandardStream::stderr(ColorChoice::Always); 26 | diagnostics.emit(&mut writer, &sources)?; 27 | } 28 | 29 | let unit = result?; 30 | 31 | let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); 32 | let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; 33 | let output: i64 = rune::from_value(output)?; 34 | 35 | println!("output: {}", output); 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /examples/examples/module.rn: -------------------------------------------------------------------------------- 1 | pub fn test() { 2 | 42 3 | } 4 | -------------------------------------------------------------------------------- /examples/examples/test.rn: -------------------------------------------------------------------------------- 1 | mod module; 2 | 3 | pub fn main() { 4 | println!("A simple example: {}", module::test()); 5 | } 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /no-std/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/arrays.rn: -------------------------------------------------------------------------------- 1 | let a = [1, 2, 3, 4]; 2 | let b = [5, 6, 7, 8]; 3 | dbg!(a, b); 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/compiler_guide/closures.rn: -------------------------------------------------------------------------------- 1 | let callable = || 42; 2 | dbg!(callable()); 3 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/functions/main_function.rn: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | println!("Hello World"); 3 | } 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /scripts/book/getting_started/hello_world.rn: -------------------------------------------------------------------------------- 1 | println!("Hello World"); 2 | -------------------------------------------------------------------------------- /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/items_imports/bar.rn: -------------------------------------------------------------------------------- 1 | pub fn number() { 2 | 1 3 | } 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/book/items_imports/foo/mod.rn: -------------------------------------------------------------------------------- 1 | pub fn number() { 2 | 2 3 | } 4 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /scripts/book/items_imports/missing_item.rn.fail: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let foo = Foo::new(); 3 | } 4 | -------------------------------------------------------------------------------- /scripts/book/items_imports/modules.rn: -------------------------------------------------------------------------------- 1 | mod foo; 2 | mod bar; 3 | 4 | dbg!(foo::number() + bar::number()); 5 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/book/template_literals/basic_template.rn: -------------------------------------------------------------------------------- 1 | let age = 30; 2 | dbg!(`I am ${age} years old!`); 3 | -------------------------------------------------------------------------------- /scripts/book/template_literals/not_a_template.rn: -------------------------------------------------------------------------------- 1 | let vec = [1, 2, 3]; 2 | dbg!(`${vec}`); 3 | -------------------------------------------------------------------------------- /scripts/book/the_stack/add.rn: -------------------------------------------------------------------------------- 1 | 1 + 3 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/book/tuples/basic_tuples.rn: -------------------------------------------------------------------------------- 1 | fn foo() { 2 | (1, "test") 3 | } 4 | 5 | dbg!(foo()); 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/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 | -------------------------------------------------------------------------------- /scripts/book/types/bad_type_check.rn: -------------------------------------------------------------------------------- 1 | assert!(["hello", "world"] is String, "vectors should be strings"); 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/broken.rn: -------------------------------------------------------------------------------- 1 | let v = [1, 2, 3, 4]; 2 | 3 | dbg!(v); 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/constant_expr.rn: -------------------------------------------------------------------------------- 1 | const VALUE = 0b001 << 3; 2 | 3 | dbg!(VALUE == 8); 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/hello_world.rn: -------------------------------------------------------------------------------- 1 | println!("Hello World"); 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/json.rn: -------------------------------------------------------------------------------- 1 | let data = json::from_string("{\"key\": 42}"); 2 | dbg!(data); 3 | -------------------------------------------------------------------------------- /scripts/not_used.rn: -------------------------------------------------------------------------------- 1 | "hello world"; 2 | 'a'; 3 | [42, 42]; 4 | #{ "foo": 42, "bar": [1, 2, 3, 4] }; 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/reverse_iterator.rn: -------------------------------------------------------------------------------- 1 | for v in (0..10).iter().rev() { 2 | dbg!(v); 3 | } 4 | -------------------------------------------------------------------------------- /scripts/signal.rn: -------------------------------------------------------------------------------- 1 | println!("Waiting for ctrl-c"); 2 | signal::ctrl_c().await?; 3 | println!("Received ctrl-c event"); 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | public/* 2 | static/js -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /site/content/play.md: -------------------------------------------------------------------------------- 1 | +++ 2 | template = "play.html" 3 | +++ 4 | 5 | The REP -------------------------------------------------------------------------------- /site/content/posts/2023-10-10-is-alphabetic-doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/site/content/posts/2023-10-10-is-alphabetic-doc.png -------------------------------------------------------------------------------- /site/content/posts/2023-10-10-my-project-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/site/content/posts/2023-10-10-my-project-cli.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /site/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rune-rs/rune/10dd6f64baaa3b37982e4b52f734007cbb7011bc/site/static/img/logo.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /site/templates/shortcodes/quote.html: -------------------------------------------------------------------------------- 1 |
2 | {{body}}
3 | {% if author %} 4 | -- {{ author }} 5 | {% endif %} 6 |
7 | -------------------------------------------------------------------------------- /site/templates/shortcodes/vm.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /site/templates/shortcodes/yt.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tools/builder/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tools/builder/README.md: -------------------------------------------------------------------------------- 1 | # builder 2 | 3 | A utility project for building and packaging Rune binaries. 4 | -------------------------------------------------------------------------------- /tools/generate/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tools/site/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tools/site/README.md: -------------------------------------------------------------------------------- 1 | # site 2 | 3 | A small utility to build the guts of https://rune-rs.github.io 4 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------