diff --git a/.changeset/two-drinks-check.md b/.changeset/two-drinks-check.md new file mode 100644 index 0000000000..6cea204da0 --- /dev/null +++ b/.changeset/two-drinks-check.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": patch +--- + +fix a bug where CST nodes are invalidated after using AST types diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/ast.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/ast.wit.jinja2 index 2aceef75c9..7a63444bd2 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/ast.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/ast.wit.jinja2 @@ -2,9 +2,9 @@ interface ast { use cst.{node, nonterminal-node}; resource selectors { - sequence: static func(node: nonterminal-node) -> result>, string>; - choice: static func(node: nonterminal-node) -> result; - repeated: static func(node: nonterminal-node) -> result, string>; - separated: static func(node: nonterminal-node) -> result>, string>; + sequence: static func(node: borrow) -> result>, string>; + choice: static func(node: borrow) -> result; + repeated: static func(node: borrow) -> result, string>; + separated: static func(node: borrow) -> result>, string>; } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/ast.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/ast.wit index 31c6a91f88..16ed171036 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/ast.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/ast.wit @@ -4,9 +4,9 @@ interface ast { use cst.{node, nonterminal-node}; resource selectors { - sequence: static func(node: nonterminal-node) -> result>, string>; - choice: static func(node: nonterminal-node) -> result; - repeated: static func(node: nonterminal-node) -> result, string>; - separated: static func(node: nonterminal-node) -> result>, string>; + sequence: static func(node: borrow) -> result>, string>; + choice: static func(node: borrow) -> result; + repeated: static func(node: borrow) -> result, string>; + separated: static func(node: borrow) -> result>, string>; } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs index 1a4b3c6eee..10b4fb6b87 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs @@ -8,7 +8,7 @@ mod ffi { Guest, GuestSelectors, }; pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ - Node, NonterminalNode, + Node, NonterminalNodeBorrow, }; } @@ -27,25 +27,25 @@ impl ffi::Guest for crate::wasm_crate::World { pub struct SelectorsWrapper; impl ffi::GuestSelectors for SelectorsWrapper { - fn sequence(node: ffi::NonterminalNode) -> Result>, String> { + fn sequence(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_sequence(node._borrow_ffi())? .into_iter() .map(|opt| opt.map(|node| node._into_ffi())) .collect()) } - fn choice(node: ffi::NonterminalNode) -> Result { + fn choice(node: ffi::NonterminalNodeBorrow<'_>) -> Result { Ok(selectors::select_choice(node._borrow_ffi())?._into_ffi()) } - fn repeated(node: ffi::NonterminalNode) -> Result, String> { + fn repeated(node: ffi::NonterminalNodeBorrow<'_>) -> Result, String> { Ok(selectors::select_repeated(node._borrow_ffi())? .into_iter() .map(|node| node._into_ffi()) .collect()) } - fn separated(node: ffi::NonterminalNode) -> Result>, String> { + fn separated(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_separated(node._borrow_ffi())? .into_iter() .map(|vec| vec.into_iter().map(|node| node._into_ffi()).collect()) diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/ast.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/ast.wit index 31c6a91f88..16ed171036 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/ast.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/ast.wit @@ -4,9 +4,9 @@ interface ast { use cst.{node, nonterminal-node}; resource selectors { - sequence: static func(node: nonterminal-node) -> result>, string>; - choice: static func(node: nonterminal-node) -> result; - repeated: static func(node: nonterminal-node) -> result, string>; - separated: static func(node: nonterminal-node) -> result>, string>; + sequence: static func(node: borrow) -> result>, string>; + choice: static func(node: borrow) -> result; + repeated: static func(node: borrow) -> result, string>; + separated: static func(node: borrow) -> result>, string>; } } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs index 5b262a1782..cf50ecacd2 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs @@ -10,7 +10,7 @@ mod ffi { Guest, GuestSelectors, }; pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ - Node, NonterminalNode, + Node, NonterminalNodeBorrow, }; } @@ -29,25 +29,25 @@ impl ffi::Guest for crate::wasm_crate::World { pub struct SelectorsWrapper; impl ffi::GuestSelectors for SelectorsWrapper { - fn sequence(node: ffi::NonterminalNode) -> Result>, String> { + fn sequence(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_sequence(node._borrow_ffi())? .into_iter() .map(|opt| opt.map(|node| node._into_ffi())) .collect()) } - fn choice(node: ffi::NonterminalNode) -> Result { + fn choice(node: ffi::NonterminalNodeBorrow<'_>) -> Result { Ok(selectors::select_choice(node._borrow_ffi())?._into_ffi()) } - fn repeated(node: ffi::NonterminalNode) -> Result, String> { + fn repeated(node: ffi::NonterminalNodeBorrow<'_>) -> Result, String> { Ok(selectors::select_repeated(node._borrow_ffi())? .into_iter() .map(|node| node._into_ffi()) .collect()) } - fn separated(node: ffi::NonterminalNode) -> Result>, String> { + fn separated(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_separated(node._borrow_ffi())? .into_iter() .map(|vec| vec.into_iter().map(|node| node._into_ffi()).collect()) diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/ast.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/ast.wit index 31c6a91f88..16ed171036 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/ast.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/ast.wit @@ -4,9 +4,9 @@ interface ast { use cst.{node, nonterminal-node}; resource selectors { - sequence: static func(node: nonterminal-node) -> result>, string>; - choice: static func(node: nonterminal-node) -> result; - repeated: static func(node: nonterminal-node) -> result, string>; - separated: static func(node: nonterminal-node) -> result>, string>; + sequence: static func(node: borrow) -> result>, string>; + choice: static func(node: borrow) -> result; + repeated: static func(node: borrow) -> result, string>; + separated: static func(node: borrow) -> result>, string>; } } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs index 5b262a1782..cf50ecacd2 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs @@ -10,7 +10,7 @@ mod ffi { Guest, GuestSelectors, }; pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ - Node, NonterminalNode, + Node, NonterminalNodeBorrow, }; } @@ -29,25 +29,25 @@ impl ffi::Guest for crate::wasm_crate::World { pub struct SelectorsWrapper; impl ffi::GuestSelectors for SelectorsWrapper { - fn sequence(node: ffi::NonterminalNode) -> Result>, String> { + fn sequence(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_sequence(node._borrow_ffi())? .into_iter() .map(|opt| opt.map(|node| node._into_ffi())) .collect()) } - fn choice(node: ffi::NonterminalNode) -> Result { + fn choice(node: ffi::NonterminalNodeBorrow<'_>) -> Result { Ok(selectors::select_choice(node._borrow_ffi())?._into_ffi()) } - fn repeated(node: ffi::NonterminalNode) -> Result, String> { + fn repeated(node: ffi::NonterminalNodeBorrow<'_>) -> Result, String> { Ok(selectors::select_repeated(node._borrow_ffi())? .into_iter() .map(|node| node._into_ffi()) .collect()) } - fn separated(node: ffi::NonterminalNode) -> Result>, String> { + fn separated(node: ffi::NonterminalNodeBorrow<'_>) -> Result>, String> { Ok(selectors::select_separated(node._borrow_ffi())? .into_iter() .map(|vec| vec.into_iter().map(|node| node._into_ffi()).collect()) diff --git a/crates/testlang/outputs/npm/tests/src/tests/ast/ast.mts b/crates/testlang/outputs/npm/tests/src/tests/ast/ast.mts index e85b9e0450..66d31e04f9 100644 --- a/crates/testlang/outputs/npm/tests/src/tests/ast/ast.mts +++ b/crates/testlang/outputs/npm/tests/src/tests/ast/ast.mts @@ -201,3 +201,22 @@ test("create and use binary expressions", () => { assertIsTerminalNode(operator, TerminalKind.Plus, "+"); assertIsTerminalNode(rightOperand.variant, TerminalKind.Identifier, "bar"); }); + +it("can reuse the same CST nodes after selectors", () => { + // Bug: https://github.com/NomicFoundation/slang/issues/1128 + + const source = `foo + bar`; + + const parser = Parser.create("1.0.0"); + const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + parseOutput.isValid(); // true + + const cst = parseOutput.tree.asNonterminalNode()!; + const ast = new SourceUnit(cst); + + expect(ast.cst.kind).toBe(NonterminalKind.SourceUnit); + + expect(ast.members.cst.kind).toBe(NonterminalKind.SourceUnitMembers); + + expect(ast.cst.kind).toBe(NonterminalKind.SourceUnit); +});