Skip to content

VM: add support for coalescing and capture-parent-scope - #1132

Merged
schungx merged 13 commits into
rhaiscript:mainfrom
schungx:vm-add-coalescing
Aug 16, 2026
Merged

VM: add support for coalescing and capture-parent-scope#1132
schungx merged 13 commits into
rhaiscript:mainfrom
schungx:vm-add-coalescing

Conversation

@schungx

@schungx schungx commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Coalesce Support

This PR adds support for coalescing operators, such as ??, ?. and ?[...] to the VM. Previously, coalescing operators are not lowered.

New opcode

A new opcode, Op::SkipIfNotUnit is introduced. This opcode is named Skip because, unlike Jump opcodes, it does not pop the value off the stack. Instead, it only inspects the value and jumps if the value is not ().

This new opcode is necessary to implement the ?? coalescing operator.

Version is bumped

Artifact version is bumped because a new flag is written for the chaining types (Step::Index, Step::Property and `Step::Method) which makes it non backwards compatible with previous written artifacts.

Implementation

?? is implemented by the new Op::SkipIfNotUnit opcode.

?[...] and ?. are implemented by adding a new flags field to the chaining types and short-circuiting where the receiver is ().

Capture Parent Scope

Rhai has a feature that, if you put a ! in a function call, it acts sorta like a "macro" -- i.e. it appears to run in-place, being able to see all variables visible at the call site.

// A function that uses the undeclared variable 'offset', which normally should raise an error.
fn offset_value(x) {
    let local_var = 999;
    x + offset
}

let offset = 10;    // Declare local variable

let result = offset_value!(42);    // call with '!'

The result is 42 + 10 = 52 instead of an error, because Rhai takes the function call as capturing the parent's scope.

Essentially it is equivalent to:

let offset = 10;    // Declare local variable

let result = {
    let local_var = 999;
    42 + offset
};

Opcode changes

Four new _CAPTURE versions of the Op::CALL_XXX opcodes are introduced.

Implementation

The flag capture_parent_scope has always been available for Expr::FnCall. When it is set to true, call functions with the current scope instead of creating an empty new one.

@schungx schungx added enhancement vm Issues related to the Rhai Grain bytecodes compiler and VM. labels Aug 14, 2026
@schungx
schungx requested a review from ImTheSquid August 14, 2026 09:04
…s that looks at the stack but does not pop from it (like SkipIfNotUnit).
Comment thread src/grain/format/abi.rs Outdated
Comment thread src/grain/bytecode/code.rs Outdated
Comment thread src/grain/bytecode/verify.rs Outdated
@schungx

schungx commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

@ImTheSquid I've reversed the re-numbering of the instructions, as well as not using any assert!.

Based on your idea, I've started working on a "capabilities" system that identified the syntax features used by an AST. Then it'll be written into the artifact instead of the feature flags. A feature not used by an artifact and not built into the client still runs fine, even if the artifact was originally written by a build that enabled such a feature.

So for example, if an artifact is written by a normal build, but loaded in a build with no_index, it still loads fine if the artifact does not use arrays at all.

Matching capabilities is fine, but we'd run into the problem of detecting corrupted bytecode, which may corrupt the capability flags, turning a required cap into not. In that case, the verifier needs to double check instructions such that they always abide by the declared capabilities.

@schungx schungx changed the title VM: add coalescing support VM: add support for coalescing and capture-parent-scope Aug 15, 2026
@schungx
schungx requested a review from ImTheSquid August 15, 2026 16:49
@schungx

schungx commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

@ImTheSquid while refining this, I discovered that the capture_parent_scope flag for function calls is not implemented by the VM -- it became a residual fragment.

It wasn't hard to implement, so I just added that in. Now the VM really has feature parity with the AST walker.

Comment thread src/grain/format/abi.rs Outdated
Comment thread src/grain/bytecode/code.rs Outdated
@schungx
schungx requested a review from ImTheSquid August 16, 2026 05:21

@ImTheSquid ImTheSquid left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small style nits, looking good for the most part!

Comment thread src/grain/bytecode/code.rs Outdated
Comment thread src/grain/vm/mod.rs Outdated
@schungx
schungx requested a review from ImTheSquid August 16, 2026 15:43
@schungx

schungx commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator Author

@ImTheSquid Changed made. Pls check it for one final round.

@schungx
schungx merged commit 7a92f96 into rhaiscript:main Aug 16, 2026
51 checks passed
@schungx
schungx deleted the vm-add-coalescing branch August 17, 2026 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement vm Issues related to the Rhai Grain bytecodes compiler and VM.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants