kanayago 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/README.md +85 -4
- data/exe/kanayago +7 -0
- data/ext/kanayago/kanayago.c +13 -4
- data/ext/kanayago/kanayago.h +1 -0
- data/ext/kanayago/string_node.c +64 -23
- data/lib/kanayago/cli.rb +115 -0
- data/lib/kanayago/lsp/diagnostics.rb +61 -0
- data/lib/kanayago/lsp/server.rb +131 -0
- data/lib/kanayago/lsp.rb +10 -0
- data/lib/kanayago/statement_node.rb +1 -1
- data/lib/kanayago/version.rb +1 -1
- data/lib/kanayago.rb +20 -1
- data/patch/3.4/kanayago.patch +139 -19
- data/patch/head/copy_target.rb +1 -0
- data/patch/head/kanayago.patch +139 -19
- metadata +24 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2ec99120dc51fa4605b265aa47d5474d7f9a3540e3d09e10f782eebebcced6f
|
|
4
|
+
data.tar.gz: 0c836dc8b6390755edbbe0a42fe5fc936bb788961c313c75e0c7c559cd61afc2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd996926d976b0dc9e48f6ee8478d65dd0c02a48dfc81e1754a087a92e10c79f6ec174c34da2eade27c563c04b4c70a638e2ed501c0002c4d5b2e8988d8c1e48
|
|
7
|
+
data.tar.gz: f8bc6647c4daed8b6ed823c7f6e2dcb65646a735f9a9a5c6818e1a514463eb38c1bcf014d106621bbd81bf6de4f71e1b5385639dd4eeb64e727281d0d5ad1a68
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Add LSP (Language Server Protocol) mode
|
|
14
|
+
- `kanayago --lsp` - Start LSP server for editor integration
|
|
15
|
+
- Provides real-time syntax error diagnostics via LSP protocol
|
|
16
|
+
- Supports `textDocument/didOpen`, `didChange`, `didClose` notifications
|
|
17
|
+
- Publishes diagnostics with `textDocument/publishDiagnostics`
|
|
18
|
+
- Compatible with LSP-compliant editors (VSCode, etc.)
|
|
19
|
+
- Add `language_server-protocol` gem dependency (~> 3.17.0)
|
|
20
|
+
- Add CLI mode for syntax checking
|
|
21
|
+
- `kanayago check 'code'` - Check Ruby code syntax directly
|
|
22
|
+
- `kanayago check --file FILE` or `-f FILE` - Check syntax of Ruby file
|
|
23
|
+
- Output "Syntax valid" for valid syntax, "Syntax invalid" for invalid syntax
|
|
24
|
+
- Exit with code 0 for valid syntax, 1 for invalid syntax or errors
|
|
25
|
+
- Add `ParseResult` class to wrap AST and error information
|
|
26
|
+
- `ParseResult#ast` - Returns the parsed AST (ScopeNode)
|
|
27
|
+
- `ParseResult#error` - Returns SyntaxError object if syntax error occurred, false otherwise
|
|
28
|
+
- `ParseResult#valid?` - Returns true if no syntax error occurred
|
|
29
|
+
- `ParseResult#invalid?` - Returns true if syntax error occurred
|
|
30
|
+
- `Kanayago.parse` now returns `ParseResult` instead of raw AST
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Fix parser crash on syntax errors by implementing `rb_syntax_error_append`
|
|
34
|
+
- Previously, `rb_syntax_error_append` was not available in UniversalParser, causing forced termination when syntax errors occurred during parsing
|
|
35
|
+
- Ported `err_vcatf`, `syntax_error_with_path`, and `rb_syntax_error_append` from Ruby's error.c
|
|
36
|
+
- Added proper copyright notice (Copyright (C) 1993-2007 Yukihiro Matsumoto) as the code is ported from Ruby's error.c
|
|
37
|
+
- Updated patch files for both Ruby 3.4 and head versions
|
|
38
|
+
- Syntax errors now display properly instead of crashing the parser
|
|
39
|
+
- Implement error_tolerant mode to continue parsing despite syntax errors
|
|
40
|
+
- Enable `rb_ruby_parser_error_tolerant` flag for all parsing operations
|
|
41
|
+
- Parser now accumulates syntax errors in `error_buffer` instead of terminating
|
|
42
|
+
- Fixed Qfalse handling in `rb_syntax_error_append` (Qfalse is defined as 0, causing `!exc` to evaluate to true)
|
|
43
|
+
- Added OBJ_FROZEN checks to handle frozen default "compile error" messages in SyntaxError objects
|
|
44
|
+
- Both AST and error information are now available even when syntax errors occur
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
- Migrate error_buffer accessor implementation from script to patch files
|
|
48
|
+
- Moved `rb_ruby_parser_error_buffer_get` accessor function from `script/setup_parser.rb` to patch files
|
|
49
|
+
- Added parse.c modifications to both `patch/3.4/kanayago.patch` and `patch/head/kanayago.patch`
|
|
50
|
+
- Improved maintainability and version compatibility by using patch-based approach instead of runtime script modifications
|
|
51
|
+
- Removed `add_error_buffer_accessor` function from `script/setup_parser.rb`
|
|
52
|
+
- Update all test files to access AST through `ParseResult#ast`
|
|
53
|
+
- All 93 test files now use `result.ast` instead of direct result access
|
|
54
|
+
- Tests validate both successful parsing and error handling scenarios
|
|
55
|
+
|
|
56
|
+
## [0.4.1]
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- Fix segmentation fault when parsing dynamic symbols in complex hash structures
|
|
60
|
+
- Fix segmentation fault when parsing nested modules with outer constant references
|
|
61
|
+
- Fix `module_node_new` to use `RNODE_MODULE` instead of incorrect `RNODE_CLASS` macro
|
|
62
|
+
- Add NULL pointer checks in `dynamic_string_node_new`, `dynamic_symbol_node_new`, `dynamic_execute_string_node_new`, and `dynamic_regexp_node_new`
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
- Remove incorrect `@super` field access from `ModuleNode` (modules do not have superclasses)
|
|
66
|
+
|
|
10
67
|
## [0.4.0]
|
|
11
68
|
|
|
12
69
|
### Added
|
data/README.md
CHANGED
|
@@ -31,24 +31,105 @@ Finally, build `Kanayago` gem and install it.
|
|
|
31
31
|
|
|
32
32
|
```console
|
|
33
33
|
bundle exec rake build
|
|
34
|
-
gem install pkg/kanayago-0.
|
|
34
|
+
gem install pkg/kanayago-0.5.0.gem
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Usage
|
|
38
38
|
|
|
39
|
+
### Language Server Protocol (LSP) Mode
|
|
40
|
+
|
|
41
|
+
Kanayago provides LSP server support for real-time syntax checking in your editor:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Start LSP server
|
|
45
|
+
$ kanayago --lsp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This starts an LSP server that communicates via stdin/stdout. You can integrate it with LSP-compliant editors like VSCode, Vim, Emacs, etc.
|
|
49
|
+
|
|
50
|
+
#### VSCode Integration Example
|
|
51
|
+
|
|
52
|
+
Create or modify `.vscode/settings.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"ruby.lsp.enabled": false,
|
|
57
|
+
"ruby.languageServer": "kanayago-lsp",
|
|
58
|
+
"ruby.languageServerPath": "kanayago",
|
|
59
|
+
"ruby.languageServerArgs": ["--lsp"]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Now VSCode will show syntax errors in real-time as you type Ruby code.
|
|
64
|
+
|
|
65
|
+
#### Vim/Neovim with coc.nvim Integration Example
|
|
66
|
+
|
|
67
|
+
Add the following to your `coc-settings.json` (`:CocConfig` in Vim):
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"languageserver": {
|
|
72
|
+
"kanayago": {
|
|
73
|
+
"command": "kanayago",
|
|
74
|
+
"args": ["--lsp"],
|
|
75
|
+
"filetypes": ["ruby"],
|
|
76
|
+
"rootPatterns": ["Gemfile", ".git"]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Now Vim/Neovim with coc.nvim will show syntax errors in real-time as you edit Ruby files.
|
|
83
|
+
|
|
84
|
+
### Command Line Interface
|
|
85
|
+
|
|
86
|
+
Kanayago provides a CLI for syntax checking:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Check Ruby code directly
|
|
90
|
+
$ kanayago check 'p 117'
|
|
91
|
+
Syntax valid
|
|
92
|
+
|
|
93
|
+
# Check Ruby code with syntax error
|
|
94
|
+
$ kanayago check 'def foo'
|
|
95
|
+
Syntax invalid
|
|
96
|
+
|
|
97
|
+
# Check a Ruby file
|
|
98
|
+
$ kanayago check --file test.rb
|
|
99
|
+
Syntax valid
|
|
100
|
+
|
|
101
|
+
# Or use the short option
|
|
102
|
+
$ kanayago check -f test.rb
|
|
103
|
+
Syntax valid
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The CLI exits with code 0 for valid syntax and code 1 for invalid syntax or errors.
|
|
107
|
+
|
|
108
|
+
### Ruby API
|
|
109
|
+
|
|
39
110
|
```ruby
|
|
40
111
|
require 'kanayago/kanayago'
|
|
41
112
|
|
|
42
113
|
result = Kanayago.parse('117 + 117')
|
|
114
|
+
# => #<Kanayago::ParseResult:0x00007f522199c5a8>
|
|
115
|
+
|
|
116
|
+
p result.ast
|
|
43
117
|
# => #<Kanayago::ScopeNode:0x00007f522199c5a8>
|
|
44
118
|
|
|
45
|
-
p result.body
|
|
119
|
+
p result.ast.body
|
|
46
120
|
# => #<Kanayago::OperatorCallNode:0x00007f5221b06358>
|
|
47
121
|
|
|
48
|
-
p result.body.recv
|
|
49
|
-
p result.body.recv.val
|
|
122
|
+
p result.ast.body.recv
|
|
123
|
+
p result.ast.body.recv.val
|
|
50
124
|
# => #<Kanayago::IntegerNode:0x00007f5221b06330>
|
|
51
125
|
# => 117
|
|
126
|
+
|
|
127
|
+
# Check for syntax errors
|
|
128
|
+
result = Kanayago.parse('def foo')
|
|
129
|
+
p result.valid?
|
|
130
|
+
# => false
|
|
131
|
+
p result.error
|
|
132
|
+
# => #<SyntaxError: syntax error, unexpected end-of-input>
|
|
52
133
|
```
|
|
53
134
|
|
|
54
135
|
## Development
|
data/exe/kanayago
ADDED
data/ext/kanayago/kanayago.c
CHANGED
|
@@ -193,9 +193,8 @@ module_node_new(const NODE *node)
|
|
|
193
193
|
{
|
|
194
194
|
VALUE obj = rb_class_new_instance(0, 0, rb_cModuleNode);
|
|
195
195
|
|
|
196
|
-
rb_ivar_set(obj, rb_intern("@cpath"), ast_to_node_instance(
|
|
197
|
-
rb_ivar_set(obj, rb_intern("@
|
|
198
|
-
rb_ivar_set(obj, rb_intern("@body"), ast_to_node_instance(RNODE_CLASS(node)->nd_body));
|
|
196
|
+
rb_ivar_set(obj, rb_intern("@cpath"), ast_to_node_instance(RNODE_MODULE(node)->nd_cpath));
|
|
197
|
+
rb_ivar_set(obj, rb_intern("@body"), ast_to_node_instance(RNODE_MODULE(node)->nd_body));
|
|
199
198
|
|
|
200
199
|
return obj;
|
|
201
200
|
}
|
|
@@ -518,12 +517,22 @@ kanayago_parse(VALUE self, VALUE source)
|
|
|
518
517
|
&ruby_parser_data_type, parser);
|
|
519
518
|
parser->parser_params = parser_params;
|
|
520
519
|
|
|
520
|
+
// Enable error tolerant parser
|
|
521
|
+
rb_ruby_parser_error_tolerant(parser_params);
|
|
521
522
|
|
|
522
523
|
VALUE vast = rb_parser_compile_string(vparser, "main", source, 0);
|
|
523
524
|
|
|
524
525
|
rb_ast_t *ast = rb_ruby_ast_data_get(vast);
|
|
526
|
+
VALUE ast_node = ast_to_node_instance(ast->body.root);
|
|
527
|
+
|
|
528
|
+
// Get error_buffer from parser_params using accessor function
|
|
529
|
+
VALUE error_buffer = rb_ruby_parser_error_buffer_get(parser_params);
|
|
525
530
|
|
|
526
|
-
|
|
531
|
+
VALUE result = rb_hash_new();
|
|
532
|
+
rb_hash_aset(result, ID2SYM(rb_intern("ast")), ast_node);
|
|
533
|
+
rb_hash_aset(result, ID2SYM(rb_intern("error")), error_buffer);
|
|
534
|
+
|
|
535
|
+
return result;
|
|
527
536
|
}
|
|
528
537
|
|
|
529
538
|
RUBY_FUNC_EXPORTED void
|
data/ext/kanayago/kanayago.h
CHANGED
|
@@ -12,6 +12,7 @@ VALUE rb_node_rational_literal_val(const NODE *);
|
|
|
12
12
|
VALUE rb_node_imaginary_literal_val(const NODE *);
|
|
13
13
|
VALUE rb_node_str_string_val(const NODE *);
|
|
14
14
|
VALUE rb_node_sym_string_val(const NODE *);
|
|
15
|
+
VALUE rb_ruby_parser_error_buffer_get(rb_parser_t *);
|
|
15
16
|
|
|
16
17
|
// Add extern for Kanayago
|
|
17
18
|
extern const rb_data_type_t ruby_parser_data_type;
|
data/ext/kanayago/string_node.c
CHANGED
|
@@ -19,12 +19,22 @@ dynamic_string_node_new(const NODE *node)
|
|
|
19
19
|
{
|
|
20
20
|
VALUE obj = rb_class_new_instance(0, 0, rb_cDynamicStringNode);
|
|
21
21
|
rb_parser_string_t *str = RNODE_DSTR(node)->string;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const NODE *nd_next = (const NODE *)RNODE_DSTR(node)->nd_next;
|
|
23
|
+
|
|
24
|
+
if (str) {
|
|
25
|
+
rb_encoding *enc = str->enc;
|
|
26
|
+
char *ptr = str->ptr;
|
|
27
|
+
long len = str->len;
|
|
28
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_enc_str_new(ptr, len, enc));
|
|
29
|
+
} else {
|
|
30
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_str_new("", 0));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (nd_next && nd_next != (NODE *)-1) {
|
|
34
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), ast_to_node_instance(nd_next));
|
|
35
|
+
} else {
|
|
36
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), Qnil);
|
|
37
|
+
}
|
|
28
38
|
|
|
29
39
|
return obj;
|
|
30
40
|
}
|
|
@@ -34,12 +44,22 @@ dynamic_symbol_node_new(const NODE *node)
|
|
|
34
44
|
{
|
|
35
45
|
VALUE obj = rb_class_new_instance(0, 0, rb_cDynamicSymbolNode);
|
|
36
46
|
rb_parser_string_t *str = RNODE_DSYM(node)->string;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
const NODE *nd_next = (const NODE *)RNODE_DSYM(node)->nd_next;
|
|
48
|
+
|
|
49
|
+
if (str) {
|
|
50
|
+
rb_encoding *enc = str->enc;
|
|
51
|
+
char *ptr = str->ptr;
|
|
52
|
+
long len = str->len;
|
|
53
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_enc_str_new(ptr, len, enc));
|
|
54
|
+
} else {
|
|
55
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_str_new("", 0));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (nd_next && nd_next != (NODE *)-1) {
|
|
59
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), ast_to_node_instance(nd_next));
|
|
60
|
+
} else {
|
|
61
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), Qnil);
|
|
62
|
+
}
|
|
43
63
|
|
|
44
64
|
return obj;
|
|
45
65
|
}
|
|
@@ -77,12 +97,22 @@ dynamic_execute_string_node_new(const NODE *node)
|
|
|
77
97
|
{
|
|
78
98
|
VALUE obj = rb_class_new_instance(0, 0, rb_cDynamicExecuteStringNode);
|
|
79
99
|
rb_parser_string_t *str = RNODE_DXSTR(node)->string;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
100
|
+
const NODE *nd_next = (const NODE *)RNODE_DXSTR(node)->nd_next;
|
|
101
|
+
|
|
102
|
+
if (str) {
|
|
103
|
+
rb_encoding *enc = str->enc;
|
|
104
|
+
char *ptr = str->ptr;
|
|
105
|
+
long len = str->len;
|
|
106
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_enc_str_new(ptr, len, enc));
|
|
107
|
+
} else {
|
|
108
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_str_new("", 0));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (nd_next && nd_next != (NODE *)-1) {
|
|
112
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), ast_to_node_instance(nd_next));
|
|
113
|
+
} else {
|
|
114
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), Qnil);
|
|
115
|
+
}
|
|
86
116
|
|
|
87
117
|
return obj;
|
|
88
118
|
}
|
|
@@ -112,13 +142,24 @@ dynamic_regexp_node_new(const NODE *node)
|
|
|
112
142
|
{
|
|
113
143
|
VALUE obj = rb_class_new_instance(0, 0, rb_cDynamicRegexpNode);
|
|
114
144
|
rb_parser_string_t *str = RNODE_DREGX(node)->string;
|
|
115
|
-
rb_encoding *enc = str->enc;
|
|
116
|
-
char *ptr = str->ptr;
|
|
117
|
-
long len = str->len;
|
|
118
145
|
long options = RNODE_DREGX(node)->as.nd_cflag;
|
|
146
|
+
const NODE *nd_next = (const NODE *)RNODE_DREGX(node)->nd_next;
|
|
147
|
+
|
|
148
|
+
if (str) {
|
|
149
|
+
rb_encoding *enc = str->enc;
|
|
150
|
+
char *ptr = str->ptr;
|
|
151
|
+
long len = str->len;
|
|
152
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_enc_str_new(ptr, len, enc));
|
|
153
|
+
} else {
|
|
154
|
+
rb_ivar_set(obj, rb_intern("@string"), rb_str_new("", 0));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (nd_next && nd_next != (NODE *)-1) {
|
|
158
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), ast_to_node_instance(nd_next));
|
|
159
|
+
} else {
|
|
160
|
+
rb_ivar_set(obj, rb_intern("@next_nodes"), Qnil);
|
|
161
|
+
}
|
|
119
162
|
|
|
120
|
-
rb_ivar_set(obj, rb_intern("@string"), rb_enc_str_new(ptr, len, enc));
|
|
121
|
-
rb_ivar_set(obj, rb_intern("@next_nodes"), ast_to_node_instance((const NODE *)RNODE_DREGX(node)->nd_next));
|
|
122
163
|
rb_ivar_set(obj, rb_intern("@options"), LONG2FIX(options));
|
|
123
164
|
|
|
124
165
|
return obj;
|
data/lib/kanayago/cli.rb
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Kanayago
|
|
6
|
+
class CLI
|
|
7
|
+
def self.start(argv)
|
|
8
|
+
new(argv).run
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(argv)
|
|
12
|
+
@argv = argv
|
|
13
|
+
@file = nil
|
|
14
|
+
@lsp_mode = false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
# Check for --lsp flag first
|
|
19
|
+
parse_global_options
|
|
20
|
+
|
|
21
|
+
if @lsp_mode
|
|
22
|
+
start_lsp_server
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if @argv.empty?
|
|
27
|
+
puts "Usage: kanayago check 'code' or kanayago check --file FILE"
|
|
28
|
+
puts ' kanayago --lsp (start LSP server)'
|
|
29
|
+
exit 1
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
command = @argv.shift
|
|
33
|
+
|
|
34
|
+
case command
|
|
35
|
+
when 'check'
|
|
36
|
+
check_command
|
|
37
|
+
else
|
|
38
|
+
puts "Unknown command: #{command}"
|
|
39
|
+
puts "Usage: kanayago check 'code' or kanayago check --file FILE"
|
|
40
|
+
puts ' kanayago --lsp (start LSP server)'
|
|
41
|
+
exit 1
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def parse_global_options
|
|
48
|
+
# Check for --lsp flag without modifying @argv for other options
|
|
49
|
+
return unless @argv.include?('--lsp')
|
|
50
|
+
|
|
51
|
+
@lsp_mode = true
|
|
52
|
+
@argv.delete('--lsp')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def start_lsp_server
|
|
56
|
+
require_relative 'lsp'
|
|
57
|
+
server = Kanayago::LSP::Server.new
|
|
58
|
+
server.start
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def check_command
|
|
62
|
+
parse_options
|
|
63
|
+
|
|
64
|
+
if @file
|
|
65
|
+
check_file(@file)
|
|
66
|
+
elsif @argv.empty?
|
|
67
|
+
puts 'Error: Please provide Ruby code or use --file option'
|
|
68
|
+
exit 1
|
|
69
|
+
else
|
|
70
|
+
code = @argv.join(' ')
|
|
71
|
+
check_code(code)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def parse_options
|
|
76
|
+
OptionParser.new do |opts|
|
|
77
|
+
opts.banner = "Usage: kanayago check [options] 'code'"
|
|
78
|
+
|
|
79
|
+
opts.on('-f FILE', '--file FILE', 'Check syntax of Ruby file') do |file|
|
|
80
|
+
@file = file
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
opts.on('-h', '--help', 'Show this message') do
|
|
84
|
+
puts opts
|
|
85
|
+
exit
|
|
86
|
+
end
|
|
87
|
+
end.parse!(@argv)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def check_code(code)
|
|
91
|
+
result = Kanayago.parse(code)
|
|
92
|
+
|
|
93
|
+
if result.valid?
|
|
94
|
+
puts 'Syntax valid'
|
|
95
|
+
exit 0
|
|
96
|
+
else
|
|
97
|
+
puts 'Syntax invalid'
|
|
98
|
+
exit 1
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def check_file(file_path)
|
|
103
|
+
unless File.exist?(file_path)
|
|
104
|
+
puts "Error: File not found: #{file_path}"
|
|
105
|
+
exit 1
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
code = File.read(file_path)
|
|
109
|
+
check_code(code)
|
|
110
|
+
rescue StandardError => e
|
|
111
|
+
puts "Error: #{e.message}"
|
|
112
|
+
exit 1
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'language_server-protocol'
|
|
4
|
+
|
|
5
|
+
module Kanayago
|
|
6
|
+
module LSP
|
|
7
|
+
# Provides diagnostics for Ruby source code using Kanayago parser
|
|
8
|
+
class DiagnosticsProvider
|
|
9
|
+
def analyze(source)
|
|
10
|
+
diagnostics = []
|
|
11
|
+
|
|
12
|
+
result = Kanayago.parse(source)
|
|
13
|
+
|
|
14
|
+
if result.invalid?
|
|
15
|
+
# Extract error information from SyntaxError
|
|
16
|
+
error = result.error
|
|
17
|
+
diagnostic = create_diagnostic(error)
|
|
18
|
+
diagnostics << diagnostic
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
diagnostics
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def create_diagnostic(error)
|
|
27
|
+
# Try to extract line and column from error message
|
|
28
|
+
# SyntaxError message format: "syntax error, unexpected ..."
|
|
29
|
+
# or with location: "(eval):2: syntax error, unexpected ..."
|
|
30
|
+
range = extract_range_from_error(error)
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
range: range,
|
|
34
|
+
severity: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
|
|
35
|
+
source: 'Kanayago',
|
|
36
|
+
message: error.message
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def extract_range_from_error(error)
|
|
41
|
+
# Try to extract line number from error message
|
|
42
|
+
# Format: "(eval):LINE: message" or just "message"
|
|
43
|
+
message = error.message
|
|
44
|
+
|
|
45
|
+
if message =~ /\(eval\):(\d+):/
|
|
46
|
+
line = ::Regexp.last_match(1).to_i - 1 # Convert to 0-based
|
|
47
|
+
{
|
|
48
|
+
start: { line: line, character: 0 },
|
|
49
|
+
end: { line: line, character: 0 }
|
|
50
|
+
}
|
|
51
|
+
else
|
|
52
|
+
# Default to line 0 if we can't extract line number
|
|
53
|
+
{
|
|
54
|
+
start: { line: 0, character: 0 },
|
|
55
|
+
end: { line: 0, character: 0 }
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'language_server-protocol'
|
|
4
|
+
require_relative 'diagnostics'
|
|
5
|
+
|
|
6
|
+
module Kanayago
|
|
7
|
+
module LSP
|
|
8
|
+
# Language Server Protocol server for Kanayago
|
|
9
|
+
class Server
|
|
10
|
+
def initialize(input: $stdin, output: $stdout)
|
|
11
|
+
@input = input
|
|
12
|
+
@output = output
|
|
13
|
+
@writer = LanguageServer::Protocol::Transport::Io::Writer.new(@output)
|
|
14
|
+
@reader = LanguageServer::Protocol::Transport::Io::Reader.new(@input)
|
|
15
|
+
@diagnostics = DiagnosticsProvider.new
|
|
16
|
+
@documents = {} # URI => content mapping
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def start
|
|
20
|
+
@reader.read do |request|
|
|
21
|
+
handle_request(request)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def handle_request(request) # rubocop:disable Metrics/CyclomaticComplexity
|
|
28
|
+
case request[:method]
|
|
29
|
+
when 'initialize'
|
|
30
|
+
handle_initialize(request)
|
|
31
|
+
when 'initialized'
|
|
32
|
+
# Client notification, no response needed
|
|
33
|
+
when 'shutdown'
|
|
34
|
+
handle_shutdown(request)
|
|
35
|
+
when 'exit'
|
|
36
|
+
exit(0)
|
|
37
|
+
when 'textDocument/didOpen'
|
|
38
|
+
handle_did_open(request)
|
|
39
|
+
when 'textDocument/didChange'
|
|
40
|
+
handle_did_change(request)
|
|
41
|
+
when 'textDocument/didClose'
|
|
42
|
+
handle_did_close(request)
|
|
43
|
+
else
|
|
44
|
+
# Unsupported method
|
|
45
|
+
send_response(request[:id], nil) if request[:id]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def handle_initialize(request)
|
|
50
|
+
result = {
|
|
51
|
+
capabilities: {
|
|
52
|
+
textDocumentSync: {
|
|
53
|
+
openClose: true,
|
|
54
|
+
change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::FULL
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
serverInfo: {
|
|
58
|
+
name: 'Kanayago LSP',
|
|
59
|
+
version: Kanayago::VERSION
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
send_response(request[:id], result)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def handle_shutdown(request)
|
|
66
|
+
send_response(request[:id], nil)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def handle_did_open(request)
|
|
70
|
+
params = request[:params]
|
|
71
|
+
uri = params[:textDocument][:uri]
|
|
72
|
+
text = params[:textDocument][:text]
|
|
73
|
+
|
|
74
|
+
@documents[uri] = text
|
|
75
|
+
publish_diagnostics(uri, text)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def handle_did_change(request)
|
|
79
|
+
params = request[:params]
|
|
80
|
+
uri = params[:textDocument][:uri]
|
|
81
|
+
|
|
82
|
+
# FULL sync: get entire content
|
|
83
|
+
text = params[:contentChanges][0][:text]
|
|
84
|
+
|
|
85
|
+
@documents[uri] = text
|
|
86
|
+
publish_diagnostics(uri, text)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def handle_did_close(request)
|
|
90
|
+
params = request[:params]
|
|
91
|
+
uri = params[:textDocument][:uri]
|
|
92
|
+
|
|
93
|
+
@documents.delete(uri)
|
|
94
|
+
# Clear diagnostics
|
|
95
|
+
publish_diagnostics(uri, nil)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def publish_diagnostics(uri, text)
|
|
99
|
+
diagnostics = text ? @diagnostics.analyze(text) : []
|
|
100
|
+
|
|
101
|
+
notification = {
|
|
102
|
+
method: 'textDocument/publishDiagnostics',
|
|
103
|
+
params: {
|
|
104
|
+
uri: uri,
|
|
105
|
+
diagnostics: diagnostics
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
send_notification(notification)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def send_response(id, result)
|
|
113
|
+
response = {
|
|
114
|
+
jsonrpc: '2.0',
|
|
115
|
+
id: id,
|
|
116
|
+
result: result
|
|
117
|
+
}
|
|
118
|
+
@writer.write(response)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def send_notification(notification)
|
|
122
|
+
message = {
|
|
123
|
+
jsonrpc: '2.0',
|
|
124
|
+
method: notification[:method],
|
|
125
|
+
params: notification[:params]
|
|
126
|
+
}
|
|
127
|
+
@writer.write(message)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/lib/kanayago/lsp.rb
ADDED
data/lib/kanayago/version.rb
CHANGED
data/lib/kanayago.rb
CHANGED
|
@@ -14,7 +14,26 @@ require_relative 'kanayago/constant_node'
|
|
|
14
14
|
|
|
15
15
|
# Parse Ruby code with Ruby's Parser(Universal Parser)
|
|
16
16
|
module Kanayago
|
|
17
|
+
class ParseResult
|
|
18
|
+
attr_reader :ast, :error
|
|
19
|
+
|
|
20
|
+
def initialize(ast, error)
|
|
21
|
+
@ast = ast
|
|
22
|
+
@error = error
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def invalid?
|
|
26
|
+
@error.is_a?(SyntaxError)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def valid?
|
|
30
|
+
!invalid?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
17
34
|
def self.parse(source)
|
|
18
|
-
kanayago_parse(source)
|
|
35
|
+
kanayago_parse(source) in { ast:, error: }
|
|
36
|
+
|
|
37
|
+
ParseResult.new(ast, error)
|
|
19
38
|
end
|
|
20
39
|
end
|
data/patch/3.4/kanayago.patch
CHANGED
|
@@ -5,7 +5,7 @@ index 8e306d1..d420a02 100644
|
|
|
5
5
|
@@ -15,6 +15,29 @@ struct lex_pointer_string {
|
|
6
6
|
long ptr;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
+// Add Ruby's Parser struct and enum for Kanayago
|
|
10
10
|
+enum lex_type {
|
|
11
11
|
+ lex_type_str,
|
|
@@ -36,10 +36,111 @@ diff --git a/ext/kanayago/ruby_parser.c b/ext/kanayago/ruby_parser.c
|
|
|
36
36
|
index 267f619..841db65 100644
|
|
37
37
|
--- a/ext/kanayago/ruby_parser.c
|
|
38
38
|
+++ b/ext/kanayago/ruby_parser.c
|
|
39
|
-
@@ -
|
|
40
|
-
|
|
39
|
+
@@ -34,6 +34,100 @@
|
|
40
|
+
|
|
41
|
+
#define parser_encoding const void
|
|
42
|
+
|
|
43
|
+
+/*
|
|
44
|
+
+ * The following functions are ported from Ruby's error.c for Kanayago:
|
|
45
|
+
+ * - err_vcatf
|
|
46
|
+
+ * - syntax_error_with_path
|
|
47
|
+
+ * - rb_syntax_error_append
|
|
48
|
+
+ *
|
|
49
|
+
+ * Copyright (C) 1993-2007 Yukihiro Matsumoto
|
|
50
|
+
+ *
|
|
51
|
+
+ * Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
|
52
|
+
+ * You can redistribute it and/or modify it under either the terms of the
|
|
53
|
+
+ * 2-clause BSDL (see the file BSDL), or the conditions below:
|
|
54
|
+
+ *
|
|
55
|
+
+ * Redistribution and use in source and binary forms, with or without
|
|
56
|
+
+ * modification, are permitted provided that the following conditions
|
|
57
|
+
+ * are met:
|
|
58
|
+
+ * 1. Redistributions of source code must retain the above copyright
|
|
59
|
+
+ * notice, this list of conditions and the following disclaimer.
|
|
60
|
+
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
61
|
+
+ * notice, this list of conditions and the following disclaimer in the
|
|
62
|
+
+ * documentation and/or other materials provided with the distribution.
|
|
63
|
+
+ *
|
|
64
|
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
65
|
+
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
66
|
+
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
67
|
+
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
68
|
+
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
69
|
+
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
70
|
+
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
71
|
+
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
72
|
+
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
73
|
+
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
74
|
+
+ * SUCH DAMAGE.
|
|
75
|
+
+ */
|
|
76
|
+
+
|
|
77
|
+
+static VALUE
|
|
78
|
+
+err_vcatf(VALUE str, const char *pre, const char *file, int line,
|
|
79
|
+
+ const char *fmt, va_list args)
|
|
80
|
+
+{
|
|
81
|
+
+ if (file) {
|
|
82
|
+
+ rb_str_cat_cstr(str, file);
|
|
83
|
+
+ if (line) rb_str_catf(str, ":%d", line);
|
|
84
|
+
+ rb_str_cat_cstr(str, ": ");
|
|
85
|
+
+ }
|
|
86
|
+
+ if (pre) rb_str_cat_cstr(str, pre);
|
|
87
|
+
+ rb_str_vcatf(str, fmt, args);
|
|
88
|
+
+ return str;
|
|
89
|
+
+}
|
|
90
|
+
+
|
|
91
|
+
+static VALUE
|
|
92
|
+
+syntax_error_with_path(VALUE exc, VALUE file, VALUE *mesg, rb_encoding *enc)
|
|
93
|
+
+{
|
|
94
|
+
+ // Create new SyntaxError if exc is nil or Qfalse (for error_tolerant mode)
|
|
95
|
+
+ if (NIL_P(exc) || exc == Qfalse) {
|
|
96
|
+
+ exc = rb_class_new_instance(0, 0, rb_eSyntaxError);
|
|
97
|
+
+ }
|
|
98
|
+
+ *mesg = rb_attr_get(exc, rb_intern("mesg"));
|
|
99
|
+
+ // Check if mesg is nil or frozen (default "compile error" may be frozen)
|
|
100
|
+
+ if (NIL_P(*mesg) || OBJ_FROZEN(*mesg)) {
|
|
101
|
+
+ *mesg = rb_enc_str_new(0, 0, enc);
|
|
102
|
+
+ rb_ivar_set(exc, rb_intern("mesg"), *mesg);
|
|
103
|
+
+ }
|
|
104
|
+
+ return exc;
|
|
105
|
+
+}
|
|
106
|
+
+
|
|
107
|
+
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
|
|
108
|
+
+VALUE
|
|
109
|
+
+rb_syntax_error_append(VALUE exc, VALUE file, int line, int column,
|
|
110
|
+
+ rb_encoding *enc, const char *fmt, va_list args)
|
|
111
|
+
+{
|
|
112
|
+
+ const char *fn = NIL_P(file) ? NULL : RSTRING_PTR(file);
|
|
113
|
+
+ if (!exc) {
|
|
114
|
+
+ // For error_tolerant mode, create SyntaxError even when writing to stderr
|
|
115
|
+
+ exc = rb_class_new_instance(0, 0, rb_eSyntaxError);
|
|
116
|
+
+ VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
|
|
117
|
+
+ // Check if mesg is nil or frozen (default "compile error" may be frozen)
|
|
118
|
+
+ if (NIL_P(mesg) || OBJ_FROZEN(mesg)) {
|
|
119
|
+
+ mesg = rb_enc_str_new(0, 0, enc);
|
|
120
|
+
+ rb_ivar_set(exc, rb_intern("mesg"), mesg);
|
|
121
|
+
+ }
|
|
122
|
+
+ err_vcatf(mesg, NULL, fn, line, fmt, args);
|
|
123
|
+
+ // Still write to stderr for compatibility
|
|
124
|
+
+ VALUE err_mesg = rb_str_dup(mesg);
|
|
125
|
+
+ rb_str_cat_cstr(err_mesg, "\n");
|
|
126
|
+
+ rb_write_error_str(err_mesg);
|
|
127
|
+
+ }
|
|
128
|
+
+ else {
|
|
129
|
+
+ VALUE mesg;
|
|
130
|
+
+ exc = syntax_error_with_path(exc, file, &mesg, enc);
|
|
131
|
+
+ err_vcatf(mesg, NULL, fn, line, fmt, args);
|
|
132
|
+
+ }
|
|
133
|
+
+
|
|
134
|
+
+ return exc;
|
|
135
|
+
+}
|
|
136
|
+
+
|
|
137
|
+
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
|
|
138
|
+
static VALUE
|
|
139
|
+
syntax_error_append(VALUE exc, VALUE file, int line, int column,
|
|
140
|
+
@@ -314,6 +408,44 @@ enc_mbc_to_codepoint(const char *p, const char *e, parser_encoding *enc)
|
|
141
|
+
|
|
41
142
|
extern VALUE rb_eArgError;
|
|
42
|
-
|
|
143
|
+
|
|
43
144
|
+// Add for Kanayago
|
|
44
145
|
+static void *
|
|
45
146
|
+xmalloc_mul_add(size_t x, size_t y, size_t z)
|
|
@@ -81,51 +182,51 @@ index 267f619..841db65 100644
|
|
|
81
182
|
static const rb_parser_config_t rb_global_parser_config = {
|
|
82
183
|
.malloc = ruby_xmalloc,
|
|
83
184
|
.calloc = ruby_xcalloc,
|
|
84
|
-
@@ -325,9 +
|
|
185
|
+
@@ -325,9 +457,9 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
85
186
|
.zalloc = zalloc,
|
|
86
187
|
.rb_memmove = memmove2,
|
|
87
188
|
.nonempty_memcpy = nonempty_memcpy,
|
|
88
189
|
- .xmalloc_mul_add = rb_xmalloc_mul_add,
|
|
89
190
|
+ .xmalloc_mul_add = xmalloc_mul_add, // use xmalloc_mul_add for Kanayago
|
|
90
|
-
|
|
191
|
+
|
|
91
192
|
- .compile_callback = rb_suppress_tracing,
|
|
92
193
|
+ .compile_callback = suppress_tracing, // use suppress_tracing for Kanayago
|
|
93
194
|
.reg_named_capture_assign = reg_named_capture_assign,
|
|
94
|
-
|
|
195
|
+
|
|
95
196
|
.attr_get = rb_attr_get,
|
|
96
|
-
@@ -335,7 +
|
|
197
|
+
@@ -335,7 +467,7 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
97
198
|
.ary_new_from_args = rb_ary_new_from_args,
|
|
98
199
|
.ary_unshift = rb_ary_unshift,
|
|
99
|
-
|
|
200
|
+
|
|
100
201
|
- .make_temporary_id = rb_make_temporary_id,
|
|
101
202
|
+ .make_temporary_id = make_temporary_id, // use make_temporary_id for Kanayago
|
|
102
203
|
.is_local_id = is_local_id2,
|
|
103
204
|
.is_attrset_id = is_attrset_id2,
|
|
104
205
|
.is_global_name_punct = is_global_name_punct,
|
|
105
|
-
@@ -365,7 +
|
|
106
|
-
|
|
206
|
+
@@ -365,7 +497,7 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
207
|
+
|
|
107
208
|
.int2num = rb_int2num_inline,
|
|
108
|
-
|
|
209
|
+
|
|
109
210
|
- .stderr_tty_p = rb_stderr_tty_p,
|
|
110
211
|
+ .stderr_tty_p = stderr_tty_p, //use stderr_tty_p for Kanayago
|
|
111
212
|
.write_error_str = rb_write_error_str,
|
|
112
213
|
.io_write = rb_io_write,
|
|
113
214
|
.io_flush = rb_io_flush,
|
|
114
|
-
@@ -412,8 +
|
|
215
|
+
@@ -412,8 +544,8 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
115
216
|
.gc_guard = gc_guard,
|
|
116
217
|
.gc_mark = rb_gc_mark,
|
|
117
|
-
|
|
218
|
+
|
|
118
219
|
- .reg_compile = rb_reg_compile,
|
|
119
220
|
- .reg_check_preprocess = rb_reg_check_preprocess,
|
|
120
221
|
+ .reg_compile = reg_compile, // use reg_compile for Kanayago
|
|
121
222
|
+ .reg_check_preprocess = reg_check_preprocess, // use reg_check_preprocess for Kanayago
|
|
122
223
|
.memcicmp = rb_memcicmp,
|
|
123
|
-
|
|
224
|
+
|
|
124
225
|
.compile_warn = rb_compile_warn,
|
|
125
|
-
@@ -443,27 +
|
|
226
|
+
@@ -443,27 +575,6 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
126
227
|
};
|
|
127
228
|
#endif
|
|
128
|
-
|
|
229
|
+
|
|
129
230
|
-enum lex_type {
|
|
130
231
|
- lex_type_str,
|
|
131
232
|
- lex_type_io,
|
|
@@ -150,13 +251,32 @@ index 267f619..841db65 100644
|
|
|
150
251
|
static void
|
|
151
252
|
parser_mark(void *ptr)
|
|
152
253
|
{
|
|
153
|
-
@@ -501,7 +
|
|
254
|
+
@@ -501,7 +612,8 @@ parser_memsize(const void *ptr)
|
|
154
255
|
return rb_ruby_parser_memsize(parser->parser_params);
|
|
155
256
|
}
|
|
156
|
-
|
|
257
|
+
|
|
157
258
|
-static const rb_data_type_t ruby_parser_data_type = {
|
|
158
259
|
+// Not static const for Kanayago
|
|
159
260
|
+const rb_data_type_t ruby_parser_data_type = {
|
|
160
261
|
"parser",
|
|
161
262
|
{
|
|
162
263
|
parser_mark,
|
|
264
|
+
diff --git a/ext/kanayago/parse.c b/ext/kanayago/parse.c
|
|
265
|
+
--- a/ext/kanayago/parse.c
|
|
266
|
+
+++ b/ext/kanayago/parse.c
|
|
267
|
+
@@ -26941,6 +26941,15 @@ ripper_value(struct parser_params *p)
|
|
268
|
+
return p->value;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
+#else /* !RIPPER */
|
|
272
|
+
+
|
|
273
|
+
+// Accessor function for error_buffer (for Kanayago)
|
|
274
|
+
+VALUE
|
|
275
|
+
+rb_ruby_parser_error_buffer_get(rb_parser_t *p)
|
|
276
|
+
+{
|
|
277
|
+
+ return p->error_buffer;
|
|
278
|
+
+}
|
|
279
|
+
+
|
|
280
|
+
#endif /* RIPPER */
|
|
281
|
+
/*
|
|
282
|
+
* Local variables:
|
data/patch/head/copy_target.rb
CHANGED
data/patch/head/kanayago.patch
CHANGED
|
@@ -5,7 +5,7 @@ index 8e306d1..d420a02 100644
|
|
|
5
5
|
@@ -15,6 +15,29 @@ struct lex_pointer_string {
|
|
6
6
|
long ptr;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
+// Add Ruby's Parser struct and enum for Kanayago
|
|
10
10
|
+enum lex_type {
|
|
11
11
|
+ lex_type_str,
|
|
@@ -36,10 +36,111 @@ diff --git a/ext/kanayago/ruby_parser.c b/ext/kanayago/ruby_parser.c
|
|
|
36
36
|
index 267f619..841db65 100644
|
|
37
37
|
--- a/ext/kanayago/ruby_parser.c
|
|
38
38
|
+++ b/ext/kanayago/ruby_parser.c
|
|
39
|
-
@@ -
|
|
40
|
-
|
|
39
|
+
@@ -34,6 +34,100 @@
|
|
40
|
+
|
|
41
|
+
#define parser_encoding const void
|
|
42
|
+
|
|
43
|
+
+/*
|
|
44
|
+
+ * The following functions are ported from Ruby's error.c for Kanayago:
|
|
45
|
+
+ * - err_vcatf
|
|
46
|
+
+ * - syntax_error_with_path
|
|
47
|
+
+ * - rb_syntax_error_append
|
|
48
|
+
+ *
|
|
49
|
+
+ * Copyright (C) 1993-2007 Yukihiro Matsumoto
|
|
50
|
+
+ *
|
|
51
|
+
+ * Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
|
52
|
+
+ * You can redistribute it and/or modify it under either the terms of the
|
|
53
|
+
+ * 2-clause BSDL (see the file BSDL), or the conditions below:
|
|
54
|
+
+ *
|
|
55
|
+
+ * Redistribution and use in source and binary forms, with or without
|
|
56
|
+
+ * modification, are permitted provided that the following conditions
|
|
57
|
+
+ * are met:
|
|
58
|
+
+ * 1. Redistributions of source code must retain the above copyright
|
|
59
|
+
+ * notice, this list of conditions and the following disclaimer.
|
|
60
|
+
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
61
|
+
+ * notice, this list of conditions and the following disclaimer in the
|
|
62
|
+
+ * documentation and/or other materials provided with the distribution.
|
|
63
|
+
+ *
|
|
64
|
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
65
|
+
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
66
|
+
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
67
|
+
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
68
|
+
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
69
|
+
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
70
|
+
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
71
|
+
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
72
|
+
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
73
|
+
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
74
|
+
+ * SUCH DAMAGE.
|
|
75
|
+
+ */
|
|
76
|
+
+
|
|
77
|
+
+static VALUE
|
|
78
|
+
+err_vcatf(VALUE str, const char *pre, const char *file, int line,
|
|
79
|
+
+ const char *fmt, va_list args)
|
|
80
|
+
+{
|
|
81
|
+
+ if (file) {
|
|
82
|
+
+ rb_str_cat_cstr(str, file);
|
|
83
|
+
+ if (line) rb_str_catf(str, ":%d", line);
|
|
84
|
+
+ rb_str_cat_cstr(str, ": ");
|
|
85
|
+
+ }
|
|
86
|
+
+ if (pre) rb_str_cat_cstr(str, pre);
|
|
87
|
+
+ rb_str_vcatf(str, fmt, args);
|
|
88
|
+
+ return str;
|
|
89
|
+
+}
|
|
90
|
+
+
|
|
91
|
+
+static VALUE
|
|
92
|
+
+syntax_error_with_path(VALUE exc, VALUE file, VALUE *mesg, rb_encoding *enc)
|
|
93
|
+
+{
|
|
94
|
+
+ // Create new SyntaxError if exc is nil or Qfalse (for error_tolerant mode)
|
|
95
|
+
+ if (NIL_P(exc) || exc == Qfalse) {
|
|
96
|
+
+ exc = rb_class_new_instance(0, 0, rb_eSyntaxError);
|
|
97
|
+
+ }
|
|
98
|
+
+ *mesg = rb_attr_get(exc, rb_intern("mesg"));
|
|
99
|
+
+ // Check if mesg is nil or frozen (default "compile error" may be frozen)
|
|
100
|
+
+ if (NIL_P(*mesg) || OBJ_FROZEN(*mesg)) {
|
|
101
|
+
+ *mesg = rb_enc_str_new(0, 0, enc);
|
|
102
|
+
+ rb_ivar_set(exc, rb_intern("mesg"), *mesg);
|
|
103
|
+
+ }
|
|
104
|
+
+ return exc;
|
|
105
|
+
+}
|
|
106
|
+
+
|
|
107
|
+
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
|
|
108
|
+
+VALUE
|
|
109
|
+
+rb_syntax_error_append(VALUE exc, VALUE file, int line, int column,
|
|
110
|
+
+ rb_encoding *enc, const char *fmt, va_list args)
|
|
111
|
+
+{
|
|
112
|
+
+ const char *fn = NIL_P(file) ? NULL : RSTRING_PTR(file);
|
|
113
|
+
+ if (!exc) {
|
|
114
|
+
+ // For error_tolerant mode, create SyntaxError even when writing to stderr
|
|
115
|
+
+ exc = rb_class_new_instance(0, 0, rb_eSyntaxError);
|
|
116
|
+
+ VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
|
|
117
|
+
+ // Check if mesg is nil or frozen (default "compile error" may be frozen)
|
|
118
|
+
+ if (NIL_P(mesg) || OBJ_FROZEN(mesg)) {
|
|
119
|
+
+ mesg = rb_enc_str_new(0, 0, enc);
|
|
120
|
+
+ rb_ivar_set(exc, rb_intern("mesg"), mesg);
|
|
121
|
+
+ }
|
|
122
|
+
+ err_vcatf(mesg, NULL, fn, line, fmt, args);
|
|
123
|
+
+ // Still write to stderr for compatibility
|
|
124
|
+
+ VALUE err_mesg = rb_str_dup(mesg);
|
|
125
|
+
+ rb_str_cat_cstr(err_mesg, "\n");
|
|
126
|
+
+ rb_write_error_str(err_mesg);
|
|
127
|
+
+ }
|
|
128
|
+
+ else {
|
|
129
|
+
+ VALUE mesg;
|
|
130
|
+
+ exc = syntax_error_with_path(exc, file, &mesg, enc);
|
|
131
|
+
+ err_vcatf(mesg, NULL, fn, line, fmt, args);
|
|
132
|
+
+ }
|
|
133
|
+
+
|
|
134
|
+
+ return exc;
|
|
135
|
+
+}
|
|
136
|
+
+
|
|
137
|
+
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
|
|
138
|
+
static VALUE
|
|
139
|
+
syntax_error_append(VALUE exc, VALUE file, int line, int column,
|
|
140
|
+
@@ -314,6 +408,44 @@ enc_mbc_to_codepoint(const char *p, const char *e, parser_encoding *enc)
|
|
141
|
+
|
|
41
142
|
extern VALUE rb_eArgError;
|
|
42
|
-
|
|
143
|
+
|
|
43
144
|
+// Add for Kanayago
|
|
44
145
|
+static void *
|
|
45
146
|
+xmalloc_mul_add(size_t x, size_t y, size_t z)
|
|
@@ -81,51 +182,51 @@ index 267f619..841db65 100644
|
|
|
81
182
|
static const rb_parser_config_t rb_global_parser_config = {
|
|
82
183
|
.malloc = ruby_xmalloc,
|
|
83
184
|
.calloc = ruby_xcalloc,
|
|
84
|
-
@@ -325,9 +
|
|
185
|
+
@@ -325,9 +457,9 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
85
186
|
.zalloc = zalloc,
|
|
86
187
|
.rb_memmove = memmove2,
|
|
87
188
|
.nonempty_memcpy = nonempty_memcpy,
|
|
88
189
|
- .xmalloc_mul_add = rb_xmalloc_mul_add,
|
|
89
190
|
+ .xmalloc_mul_add = xmalloc_mul_add, // use xmalloc_mul_add for Kanayago
|
|
90
|
-
|
|
191
|
+
|
|
91
192
|
- .compile_callback = rb_suppress_tracing,
|
|
92
193
|
+ .compile_callback = suppress_tracing, // use suppress_tracing for Kanayago
|
|
93
194
|
.reg_named_capture_assign = reg_named_capture_assign,
|
|
94
|
-
|
|
195
|
+
|
|
95
196
|
.attr_get = rb_attr_get,
|
|
96
|
-
@@ -335,7 +
|
|
197
|
+
@@ -335,7 +467,7 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
97
198
|
.ary_new_from_args = rb_ary_new_from_args,
|
|
98
199
|
.ary_unshift = rb_ary_unshift,
|
|
99
|
-
|
|
200
|
+
|
|
100
201
|
- .make_temporary_id = rb_make_temporary_id,
|
|
101
202
|
+ .make_temporary_id = make_temporary_id, // use make_temporary_id for Kanayago
|
|
102
203
|
.is_local_id = is_local_id2,
|
|
103
204
|
.is_attrset_id = is_attrset_id2,
|
|
104
205
|
.is_global_name_punct = is_global_name_punct,
|
|
105
|
-
@@ -365,7 +
|
|
106
|
-
|
|
206
|
+
@@ -365,7 +497,7 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
207
|
+
|
|
107
208
|
.int2num = rb_int2num_inline,
|
|
108
|
-
|
|
209
|
+
|
|
109
210
|
- .stderr_tty_p = rb_stderr_tty_p,
|
|
110
211
|
+ .stderr_tty_p = stderr_tty_p, //use stderr_tty_p for Kanayago
|
|
111
212
|
.write_error_str = rb_write_error_str,
|
|
112
213
|
.io_write = rb_io_write,
|
|
113
214
|
.io_flush = rb_io_flush,
|
|
114
|
-
@@ -412,8 +
|
|
215
|
+
@@ -412,8 +544,8 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
115
216
|
.gc_guard = gc_guard,
|
|
116
217
|
.gc_mark = rb_gc_mark,
|
|
117
|
-
|
|
218
|
+
|
|
118
219
|
- .reg_compile = rb_reg_compile,
|
|
119
220
|
- .reg_check_preprocess = rb_reg_check_preprocess,
|
|
120
221
|
+ .reg_compile = reg_compile, // use reg_compile for Kanayago
|
|
121
222
|
+ .reg_check_preprocess = reg_check_preprocess, // use reg_check_preprocess for Kanayago
|
|
122
223
|
.memcicmp = rb_memcicmp,
|
|
123
|
-
|
|
224
|
+
|
|
124
225
|
.compile_warn = rb_compile_warn,
|
|
125
|
-
@@ -443,27 +
|
|
226
|
+
@@ -443,27 +575,6 @@ static const rb_parser_config_t rb_global_parser_config = {
|
|
126
227
|
};
|
|
127
228
|
#endif
|
|
128
|
-
|
|
229
|
+
|
|
129
230
|
-enum lex_type {
|
|
130
231
|
- lex_type_str,
|
|
131
232
|
- lex_type_io,
|
|
@@ -150,13 +251,32 @@ index 267f619..841db65 100644
|
|
|
150
251
|
static void
|
|
151
252
|
parser_mark(void *ptr)
|
|
152
253
|
{
|
|
153
|
-
@@ -501,7 +
|
|
254
|
+
@@ -501,7 +612,8 @@ parser_memsize(const void *ptr)
|
|
154
255
|
return rb_ruby_parser_memsize(parser->parser_params);
|
|
155
256
|
}
|
|
156
|
-
|
|
257
|
+
|
|
157
258
|
-static const rb_data_type_t ruby_parser_data_type = {
|
|
158
259
|
+// Not static const for Kanayago
|
|
159
260
|
+const rb_data_type_t ruby_parser_data_type = {
|
|
160
261
|
"parser",
|
|
161
262
|
{
|
|
162
263
|
parser_mark,
|
|
264
|
+
diff --git a/ext/kanayago/parse.c b/ext/kanayago/parse.c
|
|
265
|
+
--- a/ext/kanayago/parse.c
|
|
266
|
+
+++ b/ext/kanayago/parse.c
|
|
267
|
+
@@ -27391,6 +27391,15 @@ ripper_value(struct parser_params *p)
|
|
268
|
+
return p->value;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
+#else /* !RIPPER */
|
|
272
|
+
+
|
|
273
|
+
+// Accessor function for error_buffer (for Kanayago)
|
|
274
|
+
+VALUE
|
|
275
|
+
+rb_ruby_parser_error_buffer_get(rb_parser_t *p)
|
|
276
|
+
+{
|
|
277
|
+
+ return p->error_buffer;
|
|
278
|
+
+}
|
|
279
|
+
+
|
|
280
|
+
#endif /* RIPPER */
|
|
281
|
+
/*
|
|
282
|
+
* Local variables:
|
metadata
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kanayago
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- S-H-GAMELINKS
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: language_server-protocol
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 3.17.0
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 3.17.0
|
|
12
26
|
description: Trying to Make Ruby's Parser Available as a Gem
|
|
13
27
|
email:
|
|
14
28
|
- gamelinks007@gmail.com
|
|
15
|
-
executables:
|
|
29
|
+
executables:
|
|
30
|
+
- kanayago
|
|
16
31
|
extensions:
|
|
17
32
|
- ext/kanayago/extconf.rb
|
|
18
33
|
extra_rdoc_files: []
|
|
@@ -24,6 +39,7 @@ files:
|
|
|
24
39
|
- LICENSE.txt
|
|
25
40
|
- README.md
|
|
26
41
|
- Rakefile
|
|
42
|
+
- exe/kanayago
|
|
27
43
|
- ext/kanayago/extconf.rb
|
|
28
44
|
- ext/kanayago/kanayago.c
|
|
29
45
|
- ext/kanayago/kanayago.h
|
|
@@ -41,8 +57,12 @@ files:
|
|
|
41
57
|
- ext/kanayago/variable_node.h
|
|
42
58
|
- lib/kanayago.rb
|
|
43
59
|
- lib/kanayago/call_node.rb
|
|
60
|
+
- lib/kanayago/cli.rb
|
|
44
61
|
- lib/kanayago/constant_node.rb
|
|
45
62
|
- lib/kanayago/literal_node.rb
|
|
63
|
+
- lib/kanayago/lsp.rb
|
|
64
|
+
- lib/kanayago/lsp/diagnostics.rb
|
|
65
|
+
- lib/kanayago/lsp/server.rb
|
|
46
66
|
- lib/kanayago/pattern_node.rb
|
|
47
67
|
- lib/kanayago/scope_node.rb
|
|
48
68
|
- lib/kanayago/statement_node.rb
|
|
@@ -80,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
80
100
|
- !ruby/object:Gem::Version
|
|
81
101
|
version: '0'
|
|
82
102
|
requirements: []
|
|
83
|
-
rubygems_version:
|
|
103
|
+
rubygems_version: 4.0.0.dev
|
|
84
104
|
specification_version: 4
|
|
85
105
|
summary: Trying to Make Ruby's Parser Available as a Gem
|
|
86
106
|
test_files: []
|