Skip to content

Commit

Permalink
Add debugging facilities to RuleNode/TokenNode exposed via N-API (#908)
Browse files Browse the repository at this point in the history
Closes #466 

## JSON serialization
Adds the `toJSON` method to the RuleNode/TokenNode classes with the
comment stating that it's unstable and for debugging purposes only. I
explicitly didn't type it (it's a string) as I didn't want to publicly
encode any assumptions about the shape of the data.

We can discuss further what we want to explore as part of having pure
data external interface (JSON) for Slang, whether that's exporting or
importing JSON, but I'd consider this a separate issue as it requires
more thought and design; the original issue, from what I understand, was
primarily about improving the debugging/inspection experience.

## Debugger
Adds hidden getter properties that is only eagerly evaluated by
debugger; since it's a getter function, it shouldn't add overhead to the
runtime but I have to admit, I didn't double-check that with numbers. It
adds both `__children` and `__text`, allowing to quickly explore the
tree structure recursively and also the enclosing text scope of the
node:

### vscode-js-debug (built-in to VS Code)

![image](https://github.com/NomicFoundation/slang/assets/3093213/193702fa-02b6-4853-9dcd-8af58469cf23)
### Chrome DevTools for Node

![image](https://github.com/NomicFoundation/slang/assets/3093213/a7b81836-ad7e-495c-aded-ebcc48f3bb6b)
  • Loading branch information
Xanewok authored Apr 11, 2024
1 parent 29febae commit ab3688b
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/pink-bats-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/slang": minor
---

Changed the cst.NodeType in TS to use more descriptive string values rather than 0/1 integers
5 changes: 5 additions & 0 deletions .changeset/warm-maps-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/slang": minor
---

Add RuleNode/TokenNode::toJSON() in the TypeScript API
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/codegen/parser/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ napi = { workspace = true, optional = true }
napi-derive = { workspace = true, optional = true }
nom = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true, optional = true }
strum = { workspace = true }
strum_macros = { workspace = true }

# Since the source code is copied over as-is, we need to retain exact feature set with target crate,
# i.e `slang_solidity_node_addon`.
[features]
default = ["slang_napi_interfaces"]
slang_napi_interfaces = ["dep:napi", "dep:napi-derive"]
slang_napi_interfaces = ["dep:napi", "dep:napi-derive", "dep:serde_json"]

[lints]
workspace = true
Expand Down
45 changes: 44 additions & 1 deletion crates/codegen/parser/runtime/src/napi_interface/cst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::napi_interface::{
RuleKind, RustNode, RustRuleNode, RustTextIndex, RustTokenNode, TokenKind,
};

#[napi(namespace = "cst")]
#[napi(namespace = "cst", string_enum)]
pub enum NodeType {
Rule,
Token,
Expand Down Expand Up @@ -83,10 +83,45 @@ impl RuleNode {
.into()
}

#[napi(catch_unwind, js_name = "toJSON")]
/// Serialize the token node to JSON.
pub fn to_json(&self) -> String {
serde_json::to_string(&self.0).unwrap()
}

#[napi(catch_unwind)]
pub fn unparse(&self) -> String {
self.0.clone().unparse()
}

// Expose the children as a hidden (non-enumerable, don't generate type definition)
// property that's eagerly evaluated (getter) for an inspected parent object in the debugger context.
#[napi(
enumerable = false,
configurable = false,
writable = false,
getter,
js_name = "__children", // Needed; otherwise, the property name would shadow `children`.
skip_typescript,
catch_unwind
)]
pub fn __children(&self) -> Vec<Either<RuleNode, TokenNode>> {
Self::children(self)
}

// Similarly, expose the eagerly evaluated unparsed text in the debugger context.
#[napi(
enumerable = false,
configurable = false,
writable = false,
getter,
js_name = "__text",
skip_typescript,
catch_unwind
)]
pub fn __text(&self) -> String {
self.unparse()
}
}

#[napi(namespace = "cst")]
Expand Down Expand Up @@ -122,6 +157,14 @@ impl TokenNode {
self.0.text.clone()
}

#[napi(catch_unwind, js_name = "toJSON")]
/// Serialize the token node to JSON.
///
/// This method is intended for debugging purposes and may not be stable.
pub fn to_json(&self) -> String {
serde_json::to_string(&self.0).unwrap()
}

#[napi(ts_return_type = "cursor.Cursor", catch_unwind)]
pub fn create_cursor(
&self,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ crate-type = ["cdylib"]
default = ["slang_napi_interfaces"]
slang_napi_interfaces = [
# This enables '#[napi]' attributes on the Rust types imported via [lib.path] above.
"dep:serde_json",
]

[build-dependencies]
Expand All @@ -43,6 +44,7 @@ napi-derive = { workspace = true }
nom = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true, optional = true }
strum = { workspace = true }
strum_macros = { workspace = true }
thiserror = { workspace = true }
Expand Down
12 changes: 10 additions & 2 deletions crates/solidity/outputs/npm/package/src/generated/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ crate-type = ["cdylib"]
default = ["slang_napi_interfaces"]
slang_napi_interfaces = [
# This enables '#[napi]' attributes on the Rust types imported via [lib.path] above.
"dep:serde_json",
]

[build-dependencies]
Expand All @@ -43,6 +44,7 @@ napi-derive = { workspace = true }
nom = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true, optional = true }
strum = { workspace = true }
strum_macros = { workspace = true }
thiserror = { workspace = true }
Expand Down
12 changes: 10 additions & 2 deletions crates/testlang/outputs/npm/package/src/generated/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ab3688b

Please sign in to comment.