From 80114a833dc8249447c382bf457215b1a4d9e5ae Mon Sep 17 00:00:00 2001 From: Antony Blakey Date: Sun, 29 Oct 2023 03:49:36 +1100 Subject: [PATCH] Fix TS api types and add some cursor tests (#623) Co-authored-by: Igor Matuszewski --- .changeset/wise-rabbits-eat.md | 5 + .../parser/runtime/src/napi/napi_cst.rs | 22 +- .../parser/runtime/src/napi/napi_cursor.rs | 28 +- .../runtime/src/napi/napi_parse_error.rs | 2 +- .../runtime/src/napi/napi_parse_output.rs | 4 +- .../runtime/src/templates/language.rs.jinja2 | 10 +- .../cargo/crate/src/generated/language.rs | 10 +- .../crate/src/generated/napi/napi_cst.rs | 22 +- .../crate/src/generated/napi/napi_cursor.rs | 28 +- .../src/generated/napi/napi_parse_error.rs | 2 +- .../src/generated/napi/napi_parse_output.rs | 4 +- .../npm/crate/src/generated/language.rs | 10 +- .../npm/crate/src/generated/napi/napi_cst.rs | 22 +- .../crate/src/generated/napi/napi_cursor.rs | 28 +- .../src/generated/napi/napi_parse_error.rs | 2 +- .../src/generated/napi/napi_parse_output.rs | 4 +- .../npm/package/src/generated/index.d.ts | 40 +-- .../outputs/npm/tests/src/cst-cursor.ts | 264 ++++++++++++++++++ package-lock.json | 144 ++++++++++ 19 files changed, 562 insertions(+), 89 deletions(-) create mode 100644 .changeset/wise-rabbits-eat.md create mode 100644 crates/solidity/outputs/npm/tests/src/cst-cursor.ts diff --git a/.changeset/wise-rabbits-eat.md b/.changeset/wise-rabbits-eat.md new file mode 100644 index 0000000000..578457c764 --- /dev/null +++ b/.changeset/wise-rabbits-eat.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": patch +--- + +Correct the types in the TS api by adding the correct namespaces to type references diff --git a/crates/codegen/parser/runtime/src/napi/napi_cst.rs b/crates/codegen/parser/runtime/src/napi/napi_cst.rs index b65ae6543f..6875b82570 100644 --- a/crates/codegen/parser/runtime/src/napi/napi_cst.rs +++ b/crates/codegen/parser/runtime/src/napi/napi_cst.rs @@ -28,17 +28,21 @@ impl RuleNode { NodeType::Rule } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.RuleKind")] pub fn kind(&self) -> RuleKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { (&self.0.text_len).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn children(&self, env: Env) -> Vec { self.0 .children @@ -47,7 +51,7 @@ impl RuleNode { .collect() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Rule(self.0.clone()).cursor()) } @@ -60,11 +64,15 @@ impl TokenNode { NodeType::Token } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.TokenKind")] pub fn kind(&self) -> TokenKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { let text_len: RustTextIndex = (&self.0.text).into(); (&text_len).into() @@ -75,7 +83,7 @@ impl TokenNode { self.0.text.clone() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Token(self.0.clone()).cursor()) } diff --git a/crates/codegen/parser/runtime/src/napi/napi_cursor.rs b/crates/codegen/parser/runtime/src/napi/napi_cursor.rs index 74f039d054..e2889f652c 100644 --- a/crates/codegen/parser/runtime/src/napi/napi_cursor.rs +++ b/crates/codegen/parser/runtime/src/napi/napi_cursor.rs @@ -16,12 +16,12 @@ impl Cursor { Self(Box::new(cursor)) } - #[napi(getter)] + #[napi] pub fn reset(&mut self) { self.0.reset() } - #[napi(getter)] + #[napi] pub fn complete(&mut self) { self.0.complete() } @@ -41,22 +41,22 @@ impl Cursor { self.0.is_completed() } - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn node(&self, env: Env) -> JsObject { self.0.node().to_js(&env) } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextIndex")] pub fn text_offset(&self) -> TextIndex { (&self.0.text_offset()).into() } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { (&self.0.text_range()).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn path_rule_nodes(&self, env: Env) -> Vec { self.0 .path_rule_nodes() @@ -111,8 +111,12 @@ impl Cursor { } // TODO: find_matching (taking JS function) - #[napi(ts_return_type = "TokenNode | null")] - pub fn find_token_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.TokenNode | null")] + pub fn find_token_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_token_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) @@ -120,8 +124,12 @@ impl Cursor { // TODO: find_token_matching (taking JS function) - #[napi(ts_return_type = "RuleNode | null")] - pub fn find_rule_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.RuleNode | null")] + pub fn find_rule_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_rule_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) diff --git a/crates/codegen/parser/runtime/src/napi/napi_parse_error.rs b/crates/codegen/parser/runtime/src/napi/napi_parse_error.rs index 2f2c54c393..87a1458578 100644 --- a/crates/codegen/parser/runtime/src/napi/napi_parse_error.rs +++ b/crates/codegen/parser/runtime/src/napi/napi_parse_error.rs @@ -15,7 +15,7 @@ impl From for ParseError { #[napi(namespace = "parse_error")] impl ParseError { - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { self.0.text_range().into() } diff --git a/crates/codegen/parser/runtime/src/napi/napi_parse_output.rs b/crates/codegen/parser/runtime/src/napi/napi_parse_output.rs index 1e648be90d..a85a4e8091 100644 --- a/crates/codegen/parser/runtime/src/napi/napi_parse_output.rs +++ b/crates/codegen/parser/runtime/src/napi/napi_parse_output.rs @@ -14,12 +14,12 @@ impl From for ParseOutput { #[napi(namespace = "parse_output")] impl ParseOutput { - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn parse_tree(&self, env: Env) -> napi::JsObject { return self.0.parse_tree().to_js(&env); } - #[napi(getter)] + #[napi(getter, ts_return_type = "Array")] pub fn errors(&self) -> Vec { self.0.errors().iter().map(|x| x.clone().into()).collect() } diff --git a/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 b/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 index 47ddf4d5c7..7903a5f09e 100644 --- a/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 +++ b/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 @@ -227,13 +227,17 @@ impl Language { return Self::SUPPORTED_VERSIONS.iter().map(|v| v.to_string()).collect(); } - #[napi(js_name = "scan")] + #[napi(js_name = "scan", ts_return_type = "kinds.TokenKind | null")] pub fn scan_napi(&self, lexical_context: LexicalContext, input: String) -> Option { self.scan(lexical_context, input.as_str()) } - #[napi(js_name = "parse", ts_return_type = "ParseOutput")] - pub fn parse_napi(&self, production_kind: ProductionKind, input: String) -> NAPIParseOutput { + #[napi(js_name = "parse", ts_return_type = "parse_output.ParseOutput")] + pub fn parse_napi( + &self, + #[napi(ts_arg_type = "kinds.ProductionKind")] production_kind: ProductionKind, + input: String + ) -> NAPIParseOutput { self.parse(production_kind, input.as_str()).into() } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/language.rs b/crates/solidity/outputs/cargo/crate/src/generated/language.rs index a8cfe2bd86..01030f0706 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/language.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/language.rs @@ -6172,13 +6172,17 @@ impl Language { .collect(); } - #[napi(js_name = "scan")] + #[napi(js_name = "scan", ts_return_type = "kinds.TokenKind | null")] pub fn scan_napi(&self, lexical_context: LexicalContext, input: String) -> Option { self.scan(lexical_context, input.as_str()) } - #[napi(js_name = "parse", ts_return_type = "ParseOutput")] - pub fn parse_napi(&self, production_kind: ProductionKind, input: String) -> NAPIParseOutput { + #[napi(js_name = "parse", ts_return_type = "parse_output.ParseOutput")] + pub fn parse_napi( + &self, + #[napi(ts_arg_type = "kinds.ProductionKind")] production_kind: ProductionKind, + input: String, + ) -> NAPIParseOutput { self.parse(production_kind, input.as_str()).into() } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cst.rs b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cst.rs index 9bf48a98f8..0c80e2dd66 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cst.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cst.rs @@ -30,17 +30,21 @@ impl RuleNode { NodeType::Rule } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.RuleKind")] pub fn kind(&self) -> RuleKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { (&self.0.text_len).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn children(&self, env: Env) -> Vec { self.0 .children @@ -49,7 +53,7 @@ impl RuleNode { .collect() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Rule(self.0.clone()).cursor()) } @@ -62,11 +66,15 @@ impl TokenNode { NodeType::Token } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.TokenKind")] pub fn kind(&self) -> TokenKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { let text_len: RustTextIndex = (&self.0.text).into(); (&text_len).into() @@ -77,7 +85,7 @@ impl TokenNode { self.0.text.clone() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Token(self.0.clone()).cursor()) } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cursor.rs b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cursor.rs index 24f8ece2b3..e0d950f686 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cursor.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_cursor.rs @@ -18,12 +18,12 @@ impl Cursor { Self(Box::new(cursor)) } - #[napi(getter)] + #[napi] pub fn reset(&mut self) { self.0.reset() } - #[napi(getter)] + #[napi] pub fn complete(&mut self) { self.0.complete() } @@ -43,22 +43,22 @@ impl Cursor { self.0.is_completed() } - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn node(&self, env: Env) -> JsObject { self.0.node().to_js(&env) } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextIndex")] pub fn text_offset(&self) -> TextIndex { (&self.0.text_offset()).into() } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { (&self.0.text_range()).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn path_rule_nodes(&self, env: Env) -> Vec { self.0 .path_rule_nodes() @@ -113,8 +113,12 @@ impl Cursor { } // TODO: find_matching (taking JS function) - #[napi(ts_return_type = "TokenNode | null")] - pub fn find_token_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.TokenNode | null")] + pub fn find_token_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_token_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) @@ -122,8 +126,12 @@ impl Cursor { // TODO: find_token_matching (taking JS function) - #[napi(ts_return_type = "RuleNode | null")] - pub fn find_rule_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.RuleNode | null")] + pub fn find_rule_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_rule_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) diff --git a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_error.rs b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_error.rs index 5100e2c441..b5febf3bb2 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_error.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_error.rs @@ -17,7 +17,7 @@ impl From for ParseError { #[napi(namespace = "parse_error")] impl ParseError { - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { self.0.text_range().into() } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_output.rs b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_output.rs index 5e03abf061..b25b030d37 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_output.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/napi/napi_parse_output.rs @@ -16,12 +16,12 @@ impl From for ParseOutput { #[napi(namespace = "parse_output")] impl ParseOutput { - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn parse_tree(&self, env: Env) -> napi::JsObject { return self.0.parse_tree().to_js(&env); } - #[napi(getter)] + #[napi(getter, ts_return_type = "Array")] pub fn errors(&self) -> Vec { self.0.errors().iter().map(|x| x.clone().into()).collect() } diff --git a/crates/solidity/outputs/npm/crate/src/generated/language.rs b/crates/solidity/outputs/npm/crate/src/generated/language.rs index a8cfe2bd86..01030f0706 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/language.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/language.rs @@ -6172,13 +6172,17 @@ impl Language { .collect(); } - #[napi(js_name = "scan")] + #[napi(js_name = "scan", ts_return_type = "kinds.TokenKind | null")] pub fn scan_napi(&self, lexical_context: LexicalContext, input: String) -> Option { self.scan(lexical_context, input.as_str()) } - #[napi(js_name = "parse", ts_return_type = "ParseOutput")] - pub fn parse_napi(&self, production_kind: ProductionKind, input: String) -> NAPIParseOutput { + #[napi(js_name = "parse", ts_return_type = "parse_output.ParseOutput")] + pub fn parse_napi( + &self, + #[napi(ts_arg_type = "kinds.ProductionKind")] production_kind: ProductionKind, + input: String, + ) -> NAPIParseOutput { self.parse(production_kind, input.as_str()).into() } } diff --git a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cst.rs b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cst.rs index 9bf48a98f8..0c80e2dd66 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cst.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cst.rs @@ -30,17 +30,21 @@ impl RuleNode { NodeType::Rule } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.RuleKind")] pub fn kind(&self) -> RuleKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { (&self.0.text_len).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn children(&self, env: Env) -> Vec { self.0 .children @@ -49,7 +53,7 @@ impl RuleNode { .collect() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Rule(self.0.clone()).cursor()) } @@ -62,11 +66,15 @@ impl TokenNode { NodeType::Token } - #[napi(getter)] + #[napi(getter, ts_return_type = "kinds.TokenKind")] pub fn kind(&self) -> TokenKind { self.0.kind } - #[napi(getter, js_name = "textLength")] + #[napi( + getter, + js_name = "textLength", + ts_return_type = "text_index.TextIndex" + )] pub fn text_len(&self) -> TextIndex { let text_len: RustTextIndex = (&self.0.text).into(); (&text_len).into() @@ -77,7 +85,7 @@ impl TokenNode { self.0.text.clone() } - #[napi(getter)] + #[napi(getter, ts_return_type = "cursor.Cursor")] pub fn cursor(&self) -> Cursor { Cursor::new(RustNode::Token(self.0.clone()).cursor()) } diff --git a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cursor.rs b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cursor.rs index 24f8ece2b3..e0d950f686 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cursor.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_cursor.rs @@ -18,12 +18,12 @@ impl Cursor { Self(Box::new(cursor)) } - #[napi(getter)] + #[napi] pub fn reset(&mut self) { self.0.reset() } - #[napi(getter)] + #[napi] pub fn complete(&mut self) { self.0.complete() } @@ -43,22 +43,22 @@ impl Cursor { self.0.is_completed() } - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn node(&self, env: Env) -> JsObject { self.0.node().to_js(&env) } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextIndex")] pub fn text_offset(&self) -> TextIndex { (&self.0.text_offset()).into() } - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { (&self.0.text_range()).into() } - #[napi(getter, ts_return_type = "Array")] + #[napi(getter, ts_return_type = "Array")] pub fn path_rule_nodes(&self, env: Env) -> Vec { self.0 .path_rule_nodes() @@ -113,8 +113,12 @@ impl Cursor { } // TODO: find_matching (taking JS function) - #[napi(ts_return_type = "TokenNode | null")] - pub fn find_token_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.TokenNode | null")] + pub fn find_token_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_token_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) @@ -122,8 +126,12 @@ impl Cursor { // TODO: find_token_matching (taking JS function) - #[napi(ts_return_type = "RuleNode | null")] - pub fn find_rule_with_kind(&mut self, kinds: Vec, env: Env) -> Option { + #[napi(ts_return_type = "cst.RuleNode | null")] + pub fn find_rule_with_kind( + &mut self, + #[napi(ts_arg_type = "Array")] kinds: Vec, + env: Env, + ) -> Option { self.0 .find_rule_with_kind(&kinds[..]) .map(|token_node| token_node.to_js(&env)) diff --git a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_error.rs b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_error.rs index 5100e2c441..b5febf3bb2 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_error.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_error.rs @@ -17,7 +17,7 @@ impl From for ParseError { #[napi(namespace = "parse_error")] impl ParseError { - #[napi(getter)] + #[napi(getter, ts_return_type = "text_index.TextRange")] pub fn text_range(&self) -> TextRange { self.0.text_range().into() } diff --git a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_output.rs b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_output.rs index 5e03abf061..b25b030d37 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_output.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_parse_output.rs @@ -16,12 +16,12 @@ impl From for ParseOutput { #[napi(namespace = "parse_output")] impl ParseOutput { - #[napi(getter, ts_return_type = "RuleNode | TokenNode")] + #[napi(getter, ts_return_type = "cst.RuleNode | cst.TokenNode")] pub fn parse_tree(&self, env: Env) -> napi::JsObject { return self.0.parse_tree().to_js(&env); } - #[napi(getter)] + #[napi(getter, ts_return_type = "Array")] pub fn errors(&self) -> Vec { self.0.errors().iter().map(|x| x.clone().into()).collect() } diff --git a/crates/solidity/outputs/npm/package/src/generated/index.d.ts b/crates/solidity/outputs/npm/package/src/generated/index.d.ts index 48df2a608c..e21e80f7a2 100644 --- a/crates/solidity/outputs/npm/package/src/generated/index.d.ts +++ b/crates/solidity/outputs/npm/package/src/generated/index.d.ts @@ -496,8 +496,8 @@ export namespace language { constructor(version: string); get version(): string; static supportedVersions(): Array; - scan(lexicalContext: LexicalContext, input: string): TokenKind | null; - parse(productionKind: ProductionKind, input: string): ParseOutput; + scan(lexicalContext: LexicalContext, input: string): kinds.TokenKind | null; + parse(productionKind: kinds.ProductionKind, input: string): parse_output.ParseOutput; } } export namespace cst { @@ -507,30 +507,30 @@ export namespace cst { } export class RuleNode { get type(): NodeType.Rule; - get kind(): RuleKind; - get textLength(): TextIndex; - get children(): Array; - get cursor(): Cursor; + get kind(): kinds.RuleKind; + get textLength(): text_index.TextIndex; + get children(): Array; + get cursor(): cursor.Cursor; } export class TokenNode { get type(): NodeType.Token; - get kind(): TokenKind; - get textLength(): TextIndex; + get kind(): kinds.TokenKind; + get textLength(): text_index.TextIndex; get text(): string; - get cursor(): Cursor; + get cursor(): cursor.Cursor; } } export namespace cursor { export class Cursor { - get reset(): void; - get complete(): void; + reset(): void; + complete(): void; clone(): Cursor; spawn(): Cursor; get isCompleted(): boolean; - get node(): RuleNode | TokenNode; - get textOffset(): TextIndex; - get textRange(): TextRange; - get pathRuleNodes(): Array; + get node(): cst.RuleNode | cst.TokenNode; + get textOffset(): text_index.TextIndex; + get textRange(): text_index.TextRange; + get pathRuleNodes(): Array; goToNext(): boolean; goToNextNonDescendent(): boolean; goToPrevious(): boolean; @@ -540,20 +540,20 @@ export namespace cursor { goToNthChild(childNumber: number): boolean; goToNextSibling(): boolean; goToPreviousSibling(): boolean; - findTokenWithKind(kinds: Array): TokenNode | null; - findRuleWithKind(kinds: Array): RuleNode | null; + findTokenWithKind(kinds: Array): cst.TokenNode | null; + findRuleWithKind(kinds: Array): cst.RuleNode | null; } } export namespace parse_error { export class ParseError { - get textRange(): TextRange; + get textRange(): text_index.TextRange; toErrorReport(sourceId: string, source: string, withColour: boolean): string; } } export namespace parse_output { export class ParseOutput { - get parseTree(): RuleNode | TokenNode; - get errors(): Array; + get parseTree(): cst.RuleNode | cst.TokenNode; + get errors(): Array; get isValid(): boolean; } } diff --git a/crates/solidity/outputs/npm/tests/src/cst-cursor.ts b/crates/solidity/outputs/npm/tests/src/cst-cursor.ts new file mode 100644 index 0000000000..d568f6332e --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/cst-cursor.ts @@ -0,0 +1,264 @@ +import { Language } from "@nomicfoundation/slang/language"; +import { NodeType, RuleNode, TokenNode } from "@nomicfoundation/slang/cst"; +import { ProductionKind, TokenKind } from "@nomicfoundation/slang/kinds"; +import { Cursor } from "@nomicfoundation/slang/cursor"; + +test("use cursor", () => { + const source = "int256 constant z = 1 + 2;"; + const language = new Language("0.8.1"); + + const { parseTree } = language.parse(ProductionKind.SourceUnit, source); + const cursor: Cursor = parseTree.cursor; + + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("int256"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("constant"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("z"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("="); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("1"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("+"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Rule); + expect(cursor.node).toBeInstanceOf(RuleNode); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(" "); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe("2"); + expect(cursor.goToNext()).toBe(true); + expect(cursor.node.type).toBe(NodeType.Token); + expect(cursor.node).toBeInstanceOf(TokenNode); + expect((cursor.node as TokenNode).text).toBe(";"); + expect(cursor.goToNext()).toBe(false); +}); + +test("accessing the node in a cursor is slow", () => { + const source = "int256 constant z = 1 + 2;"; + const language = new Language("0.8.1"); + + const { parseTree } = language.parse(ProductionKind.SourceUnit, source); + + const cursor: Cursor = parseTree.cursor; + expect(cursor.isCompleted).toBe(false); + + // This is slow. + let access_time = 0; + { + const start = performance.now(); + for (let i = 0; i < 10; i++) { + do { + cursor.node; + } while (cursor.goToNext()); + cursor.reset(); + } + const end = performance.now(); + access_time = end - start; + } + + cursor.reset(); + + // This is faster + let no_access_time = 0; + { + const start = performance.now(); + for (let i = 0; i < 10; i++) { + do {} while (cursor.goToNext()); + cursor.reset(); + } + const end = performance.now(); + no_access_time = end - start; + } + + const ratio = access_time / no_access_time; + console.log("cursor node access ratio", ratio); + + // This is not good. + expect(ratio).toBeLessThan(10); +}); + +test("accessing the node in a cursor multiple times has a linear time cost", () => { + const source = "int256 constant z = 1 + 2;"; + const language = new Language("0.8.1"); + + const { parseTree } = language.parse(ProductionKind.SourceUnit, source); + + const cursor: Cursor = parseTree.cursor; + + // This is slow. + let multiple_access_time = 0; + { + const start = performance.now(); + for (let i = 0; i < 100; i++) { + do { + cursor.node; + cursor.node; + cursor.node; + cursor.node; + } while (cursor.goToNext()); + cursor.reset(); + } + const end = performance.now(); + multiple_access_time = end - start; + } + + cursor.reset(); + + // This is faster + let single_access_time = 0; + { + const start = performance.now(); + for (let i = 0; i < 100; i++) { + do { + cursor.node; + } while (cursor.goToNext()); + cursor.reset(); + } + const end = performance.now(); + single_access_time = end - start; + } + + const ratio = multiple_access_time / single_access_time; + console.log("cursor node multiple access ratio", ratio); + + // This is not good. + expect(ratio).toBeLessThan(4); +}); + +test("cursor find api is faster than testing the every node", () => { + const source = "int256 constant z = 1 + 2;"; + const language = new Language("0.8.1"); + + const { parseTree } = language.parse(ProductionKind.SourceUnit, source); + + const cursor: Cursor = parseTree.cursor; + expect(cursor.isCompleted).toBe(false); + + // This is slow. + let node_test_time = 0; + { + let count = 0; + const start = performance.now(); + for (let i = 0; i < 100; i++) { + do { + const node = cursor.node; + if (node.type === NodeType.Token && node.kind === TokenKind.Plus) { + count++; + } + } while (cursor.goToNext()); + cursor.reset(); + } + const end = performance.now(); + node_test_time = end - start; + expect(count).toBe(100); + } + + cursor.reset(); + + // This is faster + let cursor_find_time = 0; + { + let count = 0; + const kinds = [TokenKind.Plus]; + const start = performance.now(); + for (let i = 0; i < 100; i++) { + while (cursor.findTokenWithKind(kinds)) { + count++; + cursor.goToNext(); + } + cursor.reset(); + } + const end = performance.now(); + cursor_find_time = end - start; + expect(count).toBe(100); + } + + const ratio = node_test_time / cursor_find_time; + console.log("cursor find ratio", ratio); + + // I expected this to be a lot better than 8x. + expect(ratio).toBeGreaterThanOrEqual(5); +}); diff --git a/package-lock.json b/package-lock.json index ac0f19e563..b72c8861a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,6 +78,150 @@ "@nomicfoundation/slang-win32-x64-msvc": "0.10.1" } }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-darwin-arm64": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-arm64/-/slang-darwin-arm64-0.10.0.tgz", + "integrity": "sha512-Hkzas17WrKPpTDahbQtiZCSKnr/YBJbyFZ1zTS6BMjor2Wg+jJ+IJDSNKCRoT58dQssJ4PvamhXHCwLAkidNsA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-darwin-x64": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-x64/-/slang-darwin-x64-0.10.0.tgz", + "integrity": "sha512-VXwQqBLsewNuOM99Du+VGUNGEECr7KcEzEGolaRS8SkNU9N0ZQVoDBHgN/Lzc7ZviVCY14F4N08ew8CpSHTIgw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-arm64-gnu": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-gnu/-/slang-linux-arm64-gnu-0.10.0.tgz", + "integrity": "sha512-Ry2Tm2hmQfeJzpVXmFfbhhhCTud4/P6O2/tFLqs++HwM3TsMhoflaHmZomWkJ1E0ti5P4Mswr7HDUBbxsYYIDw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-arm64-musl": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-musl/-/slang-linux-arm64-musl-0.10.0.tgz", + "integrity": "sha512-R6BOEAobHm7FjWE2lrakP6VFgi/VlGcXybRDWFVENrx1p8qzYoMx4hZXOvCnpMPWKeicVVsh4m9aErwxK/9hrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-x64-gnu": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-gnu/-/slang-linux-x64-gnu-0.10.0.tgz", + "integrity": "sha512-AzmFXUDNGGtbz2Z7zdp7+9JynjkMLyTPmqONY49iSfPe4FWkJEb1aY94WAe+H/BKxUWBuSQpi/SpRbuQbQpLSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-x64-musl": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-musl/-/slang-linux-x64-musl-0.10.0.tgz", + "integrity": "sha512-98BGOXjUvrRRvlZxcTMcRLh+esSKTdvy05L4Fzuiak+Afe/JdAQ+jmOEoqhM8+pJMaG6bp6/hxIKK0KRzIduwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-arm64-msvc": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-arm64-msvc/-/slang-win32-arm64-msvc-0.10.0.tgz", + "integrity": "sha512-0BlZB5MqLRpNnFp6GHYpuL2mXtZZnp2xJKJJxrGB/2QgfQKH88K/AB1+W1ZPpD2cSdWLyEWnG74L6FragMK1Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-ia32-msvc": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-ia32-msvc/-/slang-win32-ia32-msvc-0.10.0.tgz", + "integrity": "sha512-Gaft2AnshwbF76UF4ULGmjz+523vC8mRehiuPFrU42gjTrBBW/807kmCbd+n+1Xo850zSdZ56GGHtI+8sU1vLA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-x64-msvc": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-x64-msvc/-/slang-win32-x64-msvc-0.10.0.tgz", + "integrity": "sha512-dwzl49fsiGZ2nqAYiG4Ps6o4C8itdoeA4QYeXcr4AZ/Y12Xw8QUJGsStmXkbZ5WIfPZdglLcIcV79+fwrc80Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "crates/solidity/outputs/npm/tests": { "name": "@slang-private/solidity-npm-tests", "devDependencies": {