ruby_tree_sitter 0.20.8.2-x86_64-darwin-20 → 1.0.0-x86_64-darwin-20
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/LICENSE +2 -1
- data/README.md +32 -18
- data/ext/tree_sitter/extconf.rb +1 -43
- data/ext/tree_sitter/input.c +1 -0
- data/ext/tree_sitter/language.c +131 -46
- data/ext/tree_sitter/logger.c +28 -12
- data/ext/tree_sitter/node.c +438 -130
- data/ext/tree_sitter/parser.c +232 -37
- data/ext/tree_sitter/query.c +197 -72
- data/ext/tree_sitter/query_cursor.c +140 -28
- data/ext/tree_sitter/repo.rb +121 -0
- data/ext/tree_sitter/tree.c +118 -34
- data/ext/tree_sitter/tree_cursor.c +205 -33
- data/ext/tree_sitter/tree_sitter.c +12 -0
- data/lib/tree_sitter/node.rb +43 -9
- data/lib/tree_sitter/tree_sitter.bundle +0 -0
- data/lib/tree_sitter/version.rb +4 -2
- data/lib/tree_sitter.rb +1 -0
- data/lib/tree_stand/ast_modifier.rb +30 -0
- data/lib/tree_stand/breadth_first_visitor.rb +54 -0
- data/lib/tree_stand/config.rb +13 -0
- data/lib/tree_stand/node.rb +224 -0
- data/lib/tree_stand/parser.rb +67 -0
- data/lib/tree_stand/range.rb +55 -0
- data/lib/tree_stand/tree.rb +123 -0
- data/lib/tree_stand/utils/printer.rb +73 -0
- data/lib/tree_stand/version.rb +7 -0
- data/lib/tree_stand/visitor.rb +127 -0
- data/lib/tree_stand/visitors/tree_walker.rb +37 -0
- data/lib/tree_stand.rb +48 -0
- data/tree_sitter.gemspec +15 -12
- metadata +37 -107
- data/test/README.md +0 -15
- data/test/test_helper.rb +0 -9
- data/test/tree_sitter/js_test.rb +0 -48
- data/test/tree_sitter/language_test.rb +0 -73
- data/test/tree_sitter/logger_test.rb +0 -70
- data/test/tree_sitter/node_test.rb +0 -355
- data/test/tree_sitter/parser_test.rb +0 -140
- data/test/tree_sitter/query_test.rb +0 -153
- data/test/tree_sitter/tree_cursor_test.rb +0 -83
- data/test/tree_sitter/tree_test.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c04e0d228ece9018552b37e99dc47435ea0619b04517d435d14989052a911e66
|
4
|
+
data.tar.gz: 51c6ffb6bc12033a384e3f6a1e934c16201892de2a5fb03a091cdabde0493123
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2312869308f29643285c83086a7288153d9943a93009fdeebae691ea2c3a0d3f53411e040638b1da85c9b53d033d7dc61659bd0c0e7c2376acaa146342afcf5
|
7
|
+
data.tar.gz: e742289452f9caac7a79565c4e004dd70040dc6fe7f431be535ea0bf098f6150a2196b64a342dfefd2beac802b46398ec12fa9b7afd443db04472328a8ed7295
|
data/LICENSE
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2022-present, Faveod SAS.
|
4
|
+
Copyright (c) 2022-present, Shopify Inc.
|
4
5
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -10,6 +10,10 @@ very old, unmaintained, and don't work with modern `tree-sitter` APIs.
|
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
13
|
+
### TreeSitter API
|
14
|
+
|
15
|
+
The TreeSitter API is a low-level Ruby binding for tree-sitter.
|
16
|
+
|
13
17
|
``` ruby
|
14
18
|
require 'tree_sitter'
|
15
19
|
|
@@ -28,32 +32,39 @@ root.each do |child|
|
|
28
32
|
end
|
29
33
|
```
|
30
34
|
|
31
|
-
|
35
|
+
The main philosophy behind the TreeSitter bindings is to do a 1:1 mapping between
|
36
|
+
tree-sitter's `C` API and `Ruby`, which makes it easier to experiment and port
|
37
|
+
ideas from different languages/bindings.
|
32
38
|
|
33
|
-
|
34
|
-
|
39
|
+
But it feels like writing some managed `C` with `Ruby`, and that's why we provide
|
40
|
+
a high-level API ([TreeStand](#treestand-api)) as well.
|
35
41
|
|
36
|
-
|
37
|
-
allows us to better experiment, and easily port ideas from other projects.
|
42
|
+
### TreeStand API
|
38
43
|
|
39
|
-
|
44
|
+
The TreeStand API is a high-level Ruby wrapper for the [TreeSitter](#treesitter-api) bindings. It
|
45
|
+
makes it easier to configure the parsers, and work with the underlying syntax tree.
|
46
|
+
```ruby
|
47
|
+
require 'tree_stand'
|
40
48
|
|
41
|
-
|
42
|
-
|
49
|
+
TreeStand.configure do
|
50
|
+
config.parser_path = "path/to/parser/folder/"
|
51
|
+
end
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
|
53
|
+
sql_parser = TreeStand::Parser.new("sql")
|
54
|
+
ruby_parser = TreeStand::Parser.new("ruby")
|
55
|
+
```
|
56
|
+
|
57
|
+
TreeStand provides an idiomatic Ruby interface to work with tree-sitter parsers.
|
47
58
|
|
48
59
|
## Dependencies
|
49
60
|
|
50
|
-
This gem is a binding for `tree-sitter`.
|
51
|
-
`tree-sitter` baked in it.
|
61
|
+
This gem is a binding for `tree-sitter`. It doesn't have a version of
|
62
|
+
`tree-sitter` baked in it by default.
|
52
63
|
|
53
64
|
You must install `tree-sitter` and make sure that their dynamic library is
|
54
65
|
accessible from `$PATH`, or build the gem with `--disable-sys-libs`, which will
|
55
66
|
download the latest tagged `tree-sitter` and build against it (see [Build from
|
56
|
-
source](docs/
|
67
|
+
source](docs/Contributing.md#build-from-source) .)
|
57
68
|
|
58
69
|
You can either install `tree-sitter` from source or through your go-to package manager.
|
59
70
|
|
@@ -88,7 +99,7 @@ brew install tree-sitter
|
|
88
99
|
From [rubygems](https://rubygems.org/gems/ruby_tree_sitter), in your `Gemfile`:
|
89
100
|
|
90
101
|
```ruby
|
91
|
-
gem 'ruby_tree_sitter', '~> 0
|
102
|
+
gem 'ruby_tree_sitter', '~> 1.0'
|
92
103
|
```
|
93
104
|
|
94
105
|
Or manually:
|
@@ -123,7 +134,7 @@ If you don't want to install from `rubygems`, `git`, or if you don't want to
|
|
123
134
|
compile on install, then download a native gem from this repository's
|
124
135
|
[releases](https://github.com/Faveod/ruby-tree-sitter/releases), or you can
|
125
136
|
compile it yourself (see [Build from
|
126
|
-
source](docs/
|
137
|
+
source](docs/Contributing.md#build-from-source) .)
|
127
138
|
|
128
139
|
In that case, you'd have to point your `Gemfile` to the `gem` as such:
|
129
140
|
|
@@ -131,6 +142,9 @@ In that case, you'd have to point your `Gemfile` to the `gem` as such:
|
|
131
142
|
gem 'tree_sitter', path: 'path/to/native/tree_sitter.gem'
|
132
143
|
```
|
133
144
|
|
145
|
+
⚠️ We're currently missing a lot of platforms and architectures. Cross-build
|
146
|
+
will come back in the near future.
|
147
|
+
|
134
148
|
### Parsers
|
135
149
|
|
136
150
|
You will have to install parsers yourself, either by:
|
@@ -157,7 +171,7 @@ See `examples` directory.
|
|
157
171
|
|
158
172
|
## Development
|
159
173
|
|
160
|
-
See [`docs/README.md`](docs/
|
174
|
+
See [`docs/README.md`](docs/Contributing.md).
|
161
175
|
|
162
176
|
## 🚧 👷♀️ Notes 👷 🚧
|
163
177
|
|
@@ -172,7 +186,7 @@ don't copy them left and right, and then expect them to work without
|
|
172
186
|
`SEGFAULT`ing and creating a black-hole in your living-room. Assume that you
|
173
187
|
have to work locally with them. If you get a `SEGFAULT`, you can debug the
|
174
188
|
native `C` code using `gdb`. You can read more on `SEGFAULT`s
|
175
|
-
[here](docs/SIGSEGV.md), and debugging [here](docs/
|
189
|
+
[here](docs/SIGSEGV.md), and debugging [here](docs/Contributing.md#Debugging).
|
176
190
|
|
177
191
|
That said, we do aim at providing an idiomatic `Ruby` interface. It should also
|
178
192
|
provide a _safer_ interface, where you don't have to worry about when and how
|
data/ext/tree_sitter/extconf.rb
CHANGED
@@ -30,7 +30,7 @@ dir_include, dir_lib =
|
|
30
30
|
if system_tree_sitter?
|
31
31
|
[
|
32
32
|
%w[/opt/include /opt/local/include /usr/include /usr/local/include],
|
33
|
-
%w[/opt/lib /opt/local/lib /usr/lib /usr/local/lib]
|
33
|
+
%w[/opt/lib /opt/local/lib /usr/lib /usr/local/lib],
|
34
34
|
]
|
35
35
|
else
|
36
36
|
repo = TreeSitter::Repo.new
|
@@ -53,48 +53,6 @@ dir_include, dir_lib =
|
|
53
53
|
repo.include_and_lib_dirs
|
54
54
|
end
|
55
55
|
|
56
|
-
# TREESITTER_SPEC = Bundler.load_gemspec('../../../../tree_sitter.gemspec')
|
57
|
-
|
58
|
-
# # def version = TREESITTER_SPEC.version.gsub(/\A(\d+\.\d+\.\d+)(\.\d+)?\z/, '\1')
|
59
|
-
|
60
|
-
# def version = '0.20.8'
|
61
|
-
|
62
|
-
# LINUX_PLATFORM_REGEX = /linux/
|
63
|
-
# DARWIN_PLATFORM_REGEX = /darwin/
|
64
|
-
|
65
|
-
# def platform = RUBY_PLATFORM
|
66
|
-
|
67
|
-
# def darwin?
|
68
|
-
# !!(platform =~ DARWIN_PLATFORM_REGEX)
|
69
|
-
# end
|
70
|
-
|
71
|
-
# def dll_ext
|
72
|
-
# darwin? ? 'dylib' : 'so'
|
73
|
-
# end
|
74
|
-
|
75
|
-
# def staging_path
|
76
|
-
# '../../stage/lib/tree_sitter'
|
77
|
-
# end
|
78
|
-
|
79
|
-
# def downloaded_dll_path
|
80
|
-
# "tree-sitter-#{version}"
|
81
|
-
# end
|
82
|
-
|
83
|
-
# def add_tree_sitter_dll_to_gem
|
84
|
-
# puts ">>>>>>>>>>>>> #{`pwd`}"
|
85
|
-
# path = "#{downloaded_dll_path}/libtree-sitter*.#{dll_ext}"
|
86
|
-
# files =
|
87
|
-
# Dir.glob(path)
|
88
|
-
# .map { |f| Pathname(f) }
|
89
|
-
# .filter { |f| !f.symlink? && f.file? }
|
90
|
-
# dll = files.first
|
91
|
-
# dst = Pathname(staging_path) / "libtree-sitter.#{dll_ext}"
|
92
|
-
# FileUtils.cp(dll, dst)
|
93
|
-
# TREESITTER_SPEC.files << dst
|
94
|
-
# end
|
95
|
-
|
96
|
-
# add_tree_sitter_dll_to_gem
|
97
|
-
|
98
56
|
# ################################## #
|
99
57
|
# Generate Makefile #
|
100
58
|
# ################################## #
|
data/ext/tree_sitter/input.c
CHANGED
data/ext/tree_sitter/language.c
CHANGED
@@ -25,45 +25,17 @@ VALUE new_language(const TSLanguage *language) {
|
|
25
25
|
return res;
|
26
26
|
}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
uint32_t length = (uint32_t)strlen(str);
|
40
|
-
bool named = RTEST(is_named);
|
41
|
-
return UINT2NUM(ts_language_symbol_for_name(SELF, str, length, named));
|
42
|
-
}
|
43
|
-
|
44
|
-
static VALUE language_field_count(VALUE self) {
|
45
|
-
return UINT2NUM(ts_language_field_count(SELF));
|
46
|
-
}
|
47
|
-
|
48
|
-
static VALUE language_field_name_for_id(VALUE self, VALUE field_id) {
|
49
|
-
return safe_str(ts_language_field_name_for_id(SELF, NUM2UINT(field_id)));
|
50
|
-
}
|
51
|
-
|
52
|
-
static VALUE language_field_id_for_name(VALUE self, VALUE name) {
|
53
|
-
TSLanguage *language = SELF;
|
54
|
-
const char *str = StringValuePtr(name);
|
55
|
-
uint32_t length = (uint32_t)RSTRING_LEN(name);
|
56
|
-
return UINT2NUM(ts_language_field_id_for_name(language, str, length));
|
57
|
-
}
|
58
|
-
|
59
|
-
static VALUE language_symbol_type(VALUE self, VALUE symbol) {
|
60
|
-
return new_symbol_type(ts_language_symbol_type(SELF, NUM2UINT(symbol)));
|
61
|
-
}
|
62
|
-
|
63
|
-
static VALUE language_version(VALUE self) {
|
64
|
-
return UINT2NUM(ts_language_version(SELF));
|
65
|
-
}
|
66
|
-
|
28
|
+
/**
|
29
|
+
* Load a language parser from disk.
|
30
|
+
*
|
31
|
+
* @raise [RuntimeError] if the parser was not found, or if it's incompatible
|
32
|
+
* with this gem.
|
33
|
+
*
|
34
|
+
* @param name [String] the parser's name.
|
35
|
+
* @param path [String] the parser's shared library (so, dylib) path on disk.
|
36
|
+
*
|
37
|
+
* @return [Language]
|
38
|
+
*/
|
67
39
|
static VALUE language_load(VALUE self, VALUE name, VALUE path) {
|
68
40
|
VALUE path_s = rb_funcall(path, rb_intern("to_s"), 0);
|
69
41
|
char *path_cstr = StringValueCStr(path_s);
|
@@ -113,22 +85,135 @@ static VALUE language_equal(VALUE self, VALUE other) {
|
|
113
85
|
return this == that ? Qtrue : Qfalse;
|
114
86
|
}
|
115
87
|
|
88
|
+
/**
|
89
|
+
* Get the number of distinct field names in the language.
|
90
|
+
*
|
91
|
+
* @return [Integer]
|
92
|
+
*/
|
93
|
+
static VALUE language_field_count(VALUE self) {
|
94
|
+
return UINT2NUM(ts_language_field_count(SELF));
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Get the numerical id for the given field name string.
|
99
|
+
*
|
100
|
+
* @param name [String]
|
101
|
+
*
|
102
|
+
* @return [Integer]
|
103
|
+
*/
|
104
|
+
static VALUE language_field_id_for_name(VALUE self, VALUE name) {
|
105
|
+
TSLanguage *language = SELF;
|
106
|
+
const char *str = StringValuePtr(name);
|
107
|
+
uint32_t length = (uint32_t)RSTRING_LEN(name);
|
108
|
+
return UINT2NUM(ts_language_field_id_for_name(language, str, length));
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Get the field name string for the given numerical id.
|
113
|
+
*
|
114
|
+
* @param field_id [Integer]
|
115
|
+
*
|
116
|
+
* @return [String]
|
117
|
+
*/
|
118
|
+
static VALUE language_field_name_for_id(VALUE self, VALUE field_id) {
|
119
|
+
return safe_str(ts_language_field_name_for_id(SELF, NUM2UINT(field_id)));
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Get the next parse state. Combine this with lookahead iterators to generate
|
124
|
+
* completion suggestions or valid symbols in error nodes. Use
|
125
|
+
* {Node#grammar_symbol} for valid symbols.
|
126
|
+
*/
|
127
|
+
static VALUE language_next_state(VALUE self, VALUE state, VALUE symbol) {
|
128
|
+
uint16_t sta = (uint16_t)NUM2UINT(state);
|
129
|
+
uint16_t sym = (uint16_t)NUM2UINT(symbol);
|
130
|
+
return UINT2NUM(ts_language_next_state(SELF, sta, sym));
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Get the number of distinct node types in the language.
|
135
|
+
*
|
136
|
+
* @return [Integer]
|
137
|
+
*/
|
138
|
+
static VALUE language_symbol_count(VALUE self) {
|
139
|
+
return UINT2NUM(ts_language_symbol_count(SELF));
|
140
|
+
}
|
141
|
+
|
142
|
+
/**
|
143
|
+
* Get a node type string for the given numerical id.
|
144
|
+
*
|
145
|
+
* @param symbol [Integer]
|
146
|
+
*
|
147
|
+
* @return [String]
|
148
|
+
*/
|
149
|
+
static VALUE language_symbol_name(VALUE self, VALUE symbol) {
|
150
|
+
return safe_str(ts_language_symbol_name(SELF, NUM2UINT(symbol)));
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* Get the numerical id for the given node type string.
|
155
|
+
*
|
156
|
+
* @param string [Symbol]
|
157
|
+
* @param is_named [Boolean]
|
158
|
+
*
|
159
|
+
* @return [Integer]
|
160
|
+
*/
|
161
|
+
static VALUE language_symbol_for_name(VALUE self, VALUE string,
|
162
|
+
VALUE is_named) {
|
163
|
+
const char *str = rb_id2name(SYM2ID(string));
|
164
|
+
uint32_t length = (uint32_t)strlen(str);
|
165
|
+
bool named = RTEST(is_named);
|
166
|
+
return UINT2NUM(ts_language_symbol_for_name(SELF, str, length, named));
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Check whether the given node type id belongs to named nodes, anonymous nodes,
|
171
|
+
* or a hidden nodes.
|
172
|
+
*
|
173
|
+
* Hidden nodes are never returned from the API.
|
174
|
+
*
|
175
|
+
* @see Node#named?
|
176
|
+
*
|
177
|
+
* @param symbol [Integer]
|
178
|
+
*
|
179
|
+
* @return [SymbolType]
|
180
|
+
*/
|
181
|
+
static VALUE language_symbol_type(VALUE self, VALUE symbol) {
|
182
|
+
return new_symbol_type(ts_language_symbol_type(SELF, NUM2UINT(symbol)));
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Get the ABI version number for this language. This version number is used
|
187
|
+
* to ensure that languages were generated by a compatible version of
|
188
|
+
* Tree-sitter.
|
189
|
+
*
|
190
|
+
* @see Parser#language=
|
191
|
+
*/
|
192
|
+
static VALUE language_version(VALUE self) {
|
193
|
+
return UINT2NUM(ts_language_version(SELF));
|
194
|
+
}
|
195
|
+
|
116
196
|
void init_language(void) {
|
117
197
|
cLanguage = rb_define_class_under(mTreeSitter, "Language", rb_cObject);
|
118
198
|
|
119
199
|
rb_define_alloc_func(cLanguage, language_allocate);
|
120
200
|
|
201
|
+
/* Module methods */
|
202
|
+
rb_define_module_function(cLanguage, "load", language_load, 2);
|
203
|
+
|
204
|
+
/* Operators */
|
205
|
+
rb_define_method(cLanguage, "==", language_equal, 1);
|
206
|
+
|
121
207
|
/* Class methods */
|
122
|
-
rb_define_method(cLanguage, "symbol_count", language_symbol_count, 0);
|
123
|
-
rb_define_method(cLanguage, "symbol_name", language_symbol_name, 1);
|
124
|
-
rb_define_method(cLanguage, "symbol_for_name", language_symbol_for_name, 2);
|
125
208
|
rb_define_method(cLanguage, "field_count", language_field_count, 0);
|
126
|
-
rb_define_method(cLanguage, "field_name_for_id", language_field_name_for_id,
|
127
|
-
1);
|
128
209
|
rb_define_method(cLanguage, "field_id_for_name", language_field_id_for_name,
|
129
210
|
1);
|
211
|
+
rb_define_method(cLanguage, "field_name_for_id", language_field_name_for_id,
|
212
|
+
1);
|
213
|
+
rb_define_method(cLanguage, "next_state", language_next_state, 2);
|
214
|
+
rb_define_method(cLanguage, "symbol_count", language_symbol_count, 0);
|
215
|
+
rb_define_method(cLanguage, "symbol_for_name", language_symbol_for_name, 2);
|
216
|
+
rb_define_method(cLanguage, "symbol_name", language_symbol_name, 1);
|
130
217
|
rb_define_method(cLanguage, "symbol_type", language_symbol_type, 1);
|
131
218
|
rb_define_method(cLanguage, "version", language_version, 0);
|
132
|
-
rb_define_module_function(cLanguage, "load", language_load, 2);
|
133
|
-
rb_define_method(cLanguage, "==", language_equal, 1);
|
134
219
|
}
|
data/ext/tree_sitter/logger.c
CHANGED
@@ -147,19 +147,35 @@ static void logger_initialize_stderr(logger_t *logger) {
|
|
147
147
|
}
|
148
148
|
}
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
150
|
+
/**
|
151
|
+
* Create a new logger.
|
152
|
+
*
|
153
|
+
* By default, it logs to stderr.
|
154
|
+
*
|
155
|
+
* You can provide your proper backend. You have to make sure that it
|
156
|
+
* exposes a +printf+, +puts+, or +write+ (lookup is done in that specific
|
157
|
+
* order). {StringIO} is a perfect candidate.
|
158
|
+
*
|
159
|
+
* You can also provide a format ({String}) if your backend supports a +printf+.
|
160
|
+
*
|
161
|
+
* @example
|
162
|
+
* backend = StringIO.new
|
163
|
+
* parser.logger = TreeSitter::Logger.new(backend)
|
164
|
+
*
|
165
|
+
* @param args [Array] The first argument is always a backend. The second
|
166
|
+
* argument is the format.
|
167
|
+
*/
|
162
168
|
static VALUE logger_initialize(int argc, VALUE *argv, VALUE self) {
|
169
|
+
// TODO:
|
170
|
+
// For now, we only take:
|
171
|
+
// argv[0] = stream
|
172
|
+
// argv[1] = format : String
|
173
|
+
// We need to add support for argv[1] : lambda/block
|
174
|
+
// case argv[1]
|
175
|
+
// in lambda => lambda
|
176
|
+
// in String => puts || printf || write
|
177
|
+
// else => write
|
178
|
+
// end
|
163
179
|
logger_t *logger = unwrap(self);
|
164
180
|
|
165
181
|
VALUE payload;
|