jruby-prism-parser 0.23.0.pre.SNAPSHOT-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +401 -0
  3. data/CODE_OF_CONDUCT.md +76 -0
  4. data/CONTRIBUTING.md +62 -0
  5. data/LICENSE.md +7 -0
  6. data/Makefile +101 -0
  7. data/README.md +98 -0
  8. data/config.yml +2902 -0
  9. data/docs/build_system.md +91 -0
  10. data/docs/configuration.md +64 -0
  11. data/docs/cruby_compilation.md +27 -0
  12. data/docs/design.md +53 -0
  13. data/docs/encoding.md +121 -0
  14. data/docs/fuzzing.md +88 -0
  15. data/docs/heredocs.md +36 -0
  16. data/docs/javascript.md +118 -0
  17. data/docs/local_variable_depth.md +229 -0
  18. data/docs/mapping.md +117 -0
  19. data/docs/parser_translation.md +34 -0
  20. data/docs/parsing_rules.md +19 -0
  21. data/docs/releasing.md +98 -0
  22. data/docs/ripper.md +36 -0
  23. data/docs/ruby_api.md +43 -0
  24. data/docs/ruby_parser_translation.md +19 -0
  25. data/docs/serialization.md +209 -0
  26. data/docs/testing.md +55 -0
  27. data/ext/prism/api_node.c +5098 -0
  28. data/ext/prism/api_pack.c +267 -0
  29. data/ext/prism/extconf.rb +110 -0
  30. data/ext/prism/extension.c +1155 -0
  31. data/ext/prism/extension.h +18 -0
  32. data/include/prism/ast.h +5807 -0
  33. data/include/prism/defines.h +102 -0
  34. data/include/prism/diagnostic.h +339 -0
  35. data/include/prism/encoding.h +265 -0
  36. data/include/prism/node.h +57 -0
  37. data/include/prism/options.h +230 -0
  38. data/include/prism/pack.h +152 -0
  39. data/include/prism/parser.h +732 -0
  40. data/include/prism/prettyprint.h +26 -0
  41. data/include/prism/regexp.h +33 -0
  42. data/include/prism/util/pm_buffer.h +155 -0
  43. data/include/prism/util/pm_char.h +205 -0
  44. data/include/prism/util/pm_constant_pool.h +209 -0
  45. data/include/prism/util/pm_list.h +97 -0
  46. data/include/prism/util/pm_memchr.h +29 -0
  47. data/include/prism/util/pm_newline_list.h +93 -0
  48. data/include/prism/util/pm_state_stack.h +42 -0
  49. data/include/prism/util/pm_string.h +150 -0
  50. data/include/prism/util/pm_string_list.h +44 -0
  51. data/include/prism/util/pm_strncasecmp.h +32 -0
  52. data/include/prism/util/pm_strpbrk.h +46 -0
  53. data/include/prism/version.h +29 -0
  54. data/include/prism.h +289 -0
  55. data/jruby-prism.jar +0 -0
  56. data/lib/prism/compiler.rb +486 -0
  57. data/lib/prism/debug.rb +206 -0
  58. data/lib/prism/desugar_compiler.rb +207 -0
  59. data/lib/prism/dispatcher.rb +2150 -0
  60. data/lib/prism/dot_visitor.rb +4634 -0
  61. data/lib/prism/dsl.rb +785 -0
  62. data/lib/prism/ffi.rb +346 -0
  63. data/lib/prism/lex_compat.rb +908 -0
  64. data/lib/prism/mutation_compiler.rb +753 -0
  65. data/lib/prism/node.rb +17864 -0
  66. data/lib/prism/node_ext.rb +212 -0
  67. data/lib/prism/node_inspector.rb +68 -0
  68. data/lib/prism/pack.rb +224 -0
  69. data/lib/prism/parse_result/comments.rb +177 -0
  70. data/lib/prism/parse_result/newlines.rb +64 -0
  71. data/lib/prism/parse_result.rb +498 -0
  72. data/lib/prism/pattern.rb +250 -0
  73. data/lib/prism/serialize.rb +1354 -0
  74. data/lib/prism/translation/parser/compiler.rb +1838 -0
  75. data/lib/prism/translation/parser/lexer.rb +335 -0
  76. data/lib/prism/translation/parser/rubocop.rb +37 -0
  77. data/lib/prism/translation/parser.rb +178 -0
  78. data/lib/prism/translation/ripper.rb +577 -0
  79. data/lib/prism/translation/ruby_parser.rb +1521 -0
  80. data/lib/prism/translation.rb +11 -0
  81. data/lib/prism/version.rb +3 -0
  82. data/lib/prism/visitor.rb +495 -0
  83. data/lib/prism.rb +99 -0
  84. data/prism.gemspec +135 -0
  85. data/rbi/prism.rbi +7767 -0
  86. data/rbi/prism_static.rbi +207 -0
  87. data/sig/prism.rbs +4773 -0
  88. data/sig/prism_static.rbs +201 -0
  89. data/src/diagnostic.c +400 -0
  90. data/src/encoding.c +5132 -0
  91. data/src/node.c +2786 -0
  92. data/src/options.c +213 -0
  93. data/src/pack.c +493 -0
  94. data/src/prettyprint.c +8881 -0
  95. data/src/prism.c +18406 -0
  96. data/src/regexp.c +638 -0
  97. data/src/serialize.c +1554 -0
  98. data/src/token_type.c +700 -0
  99. data/src/util/pm_buffer.c +190 -0
  100. data/src/util/pm_char.c +318 -0
  101. data/src/util/pm_constant_pool.c +322 -0
  102. data/src/util/pm_list.c +49 -0
  103. data/src/util/pm_memchr.c +35 -0
  104. data/src/util/pm_newline_list.c +84 -0
  105. data/src/util/pm_state_stack.c +25 -0
  106. data/src/util/pm_string.c +203 -0
  107. data/src/util/pm_string_list.c +28 -0
  108. data/src/util/pm_strncasecmp.c +24 -0
  109. data/src/util/pm_strpbrk.c +180 -0
  110. metadata +156 -0
@@ -0,0 +1,209 @@
1
+ # Serialization
2
+
3
+ Prism ships with the ability to serialize a syntax tree to a single string.
4
+ The string can then be deserialized back into a syntax tree using a language other than C.
5
+ This is useful for using the parsing logic in other tools without having to write a parser in that language.
6
+ The syntax tree still requires a copy of the original source, as for the most part it just contains byte offsets into the source string.
7
+
8
+ ## Types
9
+
10
+ Let us define some simple types for readability.
11
+
12
+ ### varuint
13
+
14
+ A variable-length unsigned integer with the value fitting in `uint32_t` using between 1 and 5 bytes, using the [LEB128](https://en.wikipedia.org/wiki/LEB128) encoding.
15
+ This drastically cuts down on the size of the serialized string, especially when the source file is large.
16
+
17
+ ### varsint
18
+
19
+ A variable-length signed integer with the value fitting in `int32_t` using between 1 and 5 bytes, using [ZigZag encoding](https://protobuf.dev/programming-guides/encoding/#signed-ints) into [LEB128].
20
+
21
+ ### string
22
+
23
+ | # bytes | field |
24
+ | --- | --- |
25
+ | varuint | the length of the string in bytes |
26
+ | ... | the string bytes |
27
+
28
+ ### location
29
+
30
+ | # bytes | field |
31
+ | --- | --- |
32
+ | varuint | byte offset into the source string where this location begins |
33
+ | varuint | length of the location in bytes in the source string |
34
+
35
+ ### comment
36
+
37
+ The comment type is one of:
38
+
39
+ * 0=`INLINE` (`# comment`)
40
+ * 1=`EMBEDDED_DOCUMENT` (`=begin`/`=end`)
41
+
42
+ | # bytes | field |
43
+ | --- | --- |
44
+ | `1` | comment type |
45
+ | location | the location in the source of this comment |
46
+
47
+ ### magic comment
48
+
49
+ | # bytes | field |
50
+ | --- | --- |
51
+ | location | the location of the key of the magic comment |
52
+ | location | the location of the value of the magic comment |
53
+
54
+ ### error
55
+
56
+ | # bytes | field |
57
+ | --- | --- |
58
+ | string | error message (ASCII-only characters) |
59
+ | location | the location in the source this error applies to |
60
+ | `1` | the level of the error: `0` for `fatal` |
61
+
62
+ ## warning
63
+
64
+ | # bytes | field |
65
+ | --- | --- |
66
+ | string | warning message (ASCII-only characters) |
67
+ | location | the location in the source this warning applies to |
68
+ | `1` | the level of the warning: `0` for `default` and `1` for `verbose` |
69
+
70
+ ## Structure
71
+
72
+ The serialized string representing the syntax tree is composed of three parts: the header, the body, and the constant pool.
73
+ The header contains information like the version of prism that serialized the tree.
74
+ The body contains the actual nodes in the tree.
75
+ The constant pool contains constants that were interned while parsing.
76
+
77
+ The header is structured like the following table:
78
+
79
+ | # bytes | field |
80
+ | --- | --- |
81
+ | `5` | "PRISM" |
82
+ | `1` | major version number |
83
+ | `1` | minor version number |
84
+ | `1` | patch version number |
85
+ | `1` | 1 indicates only semantics fields were serialized, 0 indicates all fields were serialized (including location fields) |
86
+ | string | the encoding name |
87
+ | varsint | the start line |
88
+ | varuint | number of newline offsets |
89
+ | varuint* | newline offsets |
90
+ | varuint | number of comments |
91
+ | comment* | comments |
92
+ | varuint | number of magic comments |
93
+ | magic comment* | magic comments |
94
+ | location? | the optional location of the `__END__` keyword and its contents |
95
+ | varuint | number of errors |
96
+ | error* | errors |
97
+ | varuint | number of warnings |
98
+ | warning* | warnings |
99
+ | `4` | content pool offset |
100
+ | varuint | content pool size |
101
+
102
+ After the header comes the body of the serialized string.
103
+ The body consists of a sequence of nodes that is built using a prefix traversal order of the syntax tree.
104
+ Each node is structured like the following table:
105
+
106
+ | # bytes | field |
107
+ | --- | --- |
108
+ | `1` | node type |
109
+ | location | node location |
110
+
111
+ Every field on the node is then appended to the serialized string. The fields can be determined by referencing `config.yml`. Depending on the type of field, it could take a couple of different forms, described below:
112
+
113
+ * `node` - A field that is a node. This is structured just as like parent node.
114
+ * `node?` - A field that is a node that is optionally present. If the node is not present, then a single `0` byte will be written in its place. If it is present, then it will be structured just as like parent node.
115
+ * `node[]` - A field that is an array of nodes. This is structured as a variable-length integer length, followed by the child nodes themselves.
116
+ * `string` - A field that is a string. For example, this is used as the name of the method in a call node, since it cannot directly reference the source string (as in `@-` or `foo=`). This is structured as a variable-length integer byte length, followed by the string itself (_without_ a trailing null byte).
117
+ * `constant` - A variable-length integer that represents an index in the constant pool.
118
+ * `constant?` - An optional variable-length integer that represents an index in the constant pool. If it's not present, then a single `0` byte will be written in its place.
119
+ * `location` - A field that is a location. This is structured as a variable-length integer start followed by a variable-length integer length.
120
+ * `location?` - A field that is a location that is optionally present. If the location is not present, then a single `0` byte will be written in its place. If it is present, then it will be structured just like the `location` child node.
121
+ * `uint8` - A field that is an 8-bit unsigned integer. This is structured as a single byte.
122
+ * `uint32` - A field that is a 32-bit unsigned integer. This is structured as a variable-length integer.
123
+
124
+ After the syntax tree, the content pool is serialized. This is a list of constants that were referenced from within the tree. The content pool begins at the offset specified in the header. Constants can be either "owned" (in which case their contents are embedded in the serialization) or "shared" (in which case their contents represent a slice of the source string). The most significant bit of the constant indicates whether it is owned or shared.
125
+
126
+ In the case that it is owned, the constant is structured as follows:
127
+
128
+ | # bytes | field |
129
+ | --- | --- |
130
+ | `4` | the byte offset in the serialization for the contents of the constant |
131
+ | `4` | the byte length in the serialization |
132
+
133
+ Note that you will need to mask off the most significant bit for the byte offset in the serialization. In the case that it is shared, the constant is structured as follows:
134
+
135
+ | # bytes | field |
136
+ | --- | --- |
137
+ | `4` | the byte offset in the source string for the contents of the constant |
138
+ | `4` | the byte length in the source string |
139
+
140
+ After the constant pool, the contents of the owned constants are serialized. This is just a sequence of bytes that represent the contents of the constants. At the end of the serialization, the buffer is null terminated.
141
+
142
+ ## APIs
143
+
144
+ The relevant APIs and struct definitions are listed below:
145
+
146
+ ```c
147
+ // A pm_buffer_t is a simple memory buffer that stores data in a contiguous
148
+ // block of memory. It is used to store the serialized representation of a
149
+ // prism tree.
150
+ typedef struct {
151
+ char *value;
152
+ size_t length;
153
+ size_t capacity;
154
+ } pm_buffer_t;
155
+
156
+ // Free the memory associated with the buffer.
157
+ void pm_buffer_free(pm_buffer_t *);
158
+
159
+ // Parse and serialize the AST represented by the given source to the given
160
+ // buffer.
161
+ void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t length, const char *data);
162
+ ```
163
+
164
+ Typically you would use a stack-allocated `pm_buffer_t` and call `pm_serialize_parse`, as in:
165
+
166
+ ```c
167
+ void
168
+ serialize(const uint8_t *source, size_t length) {
169
+ pm_buffer_t buffer = { 0 };
170
+ pm_serialize_parse(&buffer, source, length, NULL);
171
+
172
+ // Do something with the serialized string.
173
+
174
+ pm_buffer_free(&buffer);
175
+ }
176
+ ```
177
+
178
+ The final argument to `pm_serialize_parse` is an optional string that controls the options to the parse function. This includes all of the normal options that could be passed to `pm_parser_init` through a `pm_options_t` struct, but serialized as a string to make it easier for callers through FFI. Note that no `varuint` are used here to make it easier to produce the data for the caller, and also serialized size is less important here. The format of the data is structured as follows:
179
+
180
+ | # bytes | field |
181
+ | ------- | -------------------------- |
182
+ | `4` | the length of the filepath |
183
+ | ... | the filepath bytes |
184
+ | `4` | the line number |
185
+ | `4` | the length the encoding |
186
+ | ... | the encoding bytes |
187
+ | `1` | frozen string literal |
188
+ | `1` | suppress warnings |
189
+ | `1` | syntax version, see [pm_options_version_t](https://github.com/ruby/prism/blob/main/include/prism/options.h) for valid values |
190
+ | `4` | the number of scopes |
191
+ | ... | the scopes |
192
+
193
+ Scopes are ordered from the outermost scope to the innermost one.
194
+
195
+ Each scope is layed out as follows:
196
+
197
+ | # bytes | field |
198
+ | ------- | -------------------------- |
199
+ | `4` | the number of locals |
200
+ | ... | the locals |
201
+
202
+ Each local is layed out as follows:
203
+
204
+ | # bytes | field |
205
+ | ------- | -------------------------- |
206
+ | `4` | the length of the local |
207
+ | ... | the local bytes |
208
+
209
+ The data can be `NULL` (as seen in the example above).
data/docs/testing.md ADDED
@@ -0,0 +1,55 @@
1
+ # Testing
2
+
3
+ This document explains how to test prism, both locally, and against existing test suites.
4
+
5
+ ## Test suite
6
+
7
+ `rake test` will run all of the files in the `test/` directory. This can be conceived of as two parts: unit tests, and snapshot tests.
8
+
9
+ ### Unit tests
10
+
11
+ These test specific prism implementation details like comments, errors, and regular expressions. There are corresponding files for each thing being tested (like `test/errors_test.rb`).
12
+
13
+ ### Snapshot tests
14
+
15
+ Snapshot tests ensure that parsed output is equivalent to previous parsed output. There are many categorized examples of valid syntax within the `test/prism/fixtures/` directory. When the test suite runs, it will parse all of this syntax, and compare it against corresponding files in the `test/prism/snapshots/` directory. For example, `test/prism/fixtures/strings.txt` has a corresponding `test/prism/snapshots/strings.txt`.
16
+
17
+ If the parsed files do not match, it will raise an error. If there is not a corresponding file in the `test/prism/snapshots/` directory, one will be created so that it exists for the next test run.
18
+
19
+ ### Testing against repositories
20
+
21
+ To test the parser against a repository, you can run `FILEPATHS='/path/to/repository/**/*.rb' rake lex`. This will run the parser against every file matched by the glob pattern and check its generated tokens against those generated by ripper.
22
+
23
+ ## Local testing
24
+
25
+ As you are working, you will likely want to test your code locally. `test.rb` is ignored by git, so it can be used for local testing. There are also two executables which may help you:
26
+
27
+ 1. **bin/lex** takes a filepath and compares prism's lexed output to Ripper's lexed output. It prints any lexed output that doesn't match. It does some minor transformations to the lexed output in order to compare them, like split prism's heredoc tokens to mirror Ripper's.
28
+
29
+ ```
30
+ $ bin/lex test.rb
31
+ ```
32
+
33
+ If you would like to see the full lexed comparison, and not only the output that doesn't match, you can run with `VERBOSE=1`:
34
+
35
+ ```
36
+ $ VERBOSE=1 bin/lex test.rb
37
+ ```
38
+
39
+ `bin/lex` can also be used with `-e` and then source code, like this:
40
+
41
+ ```
42
+ $ bin/lex -e "1 + 2"
43
+ ```
44
+
45
+ 2. **bin/parse** takes a filepath and outputs prism's parsed node structure generated from reading the file.
46
+
47
+ ```
48
+ $ bin/parse test.rb
49
+ ```
50
+
51
+ `bin/parse` can also be used with `-e` and then source code, like this:
52
+
53
+ ```
54
+ $ bin/parse -e "1 + 2"
55
+ ```