prism 1.0.0 → 1.1.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.
data/src/util/pm_string.c CHANGED
@@ -47,6 +47,62 @@ pm_string_constant_init(pm_string_t *string, const char *source, size_t length)
47
47
  };
48
48
  }
49
49
 
50
+ #ifdef _WIN32
51
+ /**
52
+ * Represents a file handle on Windows, where the path will need to be freed
53
+ * when the file is closed.
54
+ */
55
+ typedef struct {
56
+ /** The path to the file, which will become allocated memory. */
57
+ WCHAR *path;
58
+
59
+ /** The handle to the file, which will start as uninitialized memory. */
60
+ HANDLE file;
61
+ } pm_string_file_handle_t;
62
+
63
+ /**
64
+ * Open the file indicated by the filepath parameter for reading on Windows.
65
+ * Perform any kind of normalization that needs to happen on the filepath.
66
+ */
67
+ static pm_string_init_result_t
68
+ pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) {
69
+ int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
70
+ if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
71
+
72
+ handle->path = xmalloc(sizeof(WCHAR) * ((size_t) length));
73
+ if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
74
+ xfree(handle->path);
75
+ return PM_STRING_INIT_ERROR_GENERIC;
76
+ }
77
+
78
+ handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
79
+ if (handle->file == INVALID_HANDLE_VALUE) {
80
+ pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
81
+
82
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
83
+ DWORD attributes = GetFileAttributesW(handle->path);
84
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
85
+ result = PM_STRING_INIT_ERROR_DIRECTORY;
86
+ }
87
+ }
88
+
89
+ xfree(handle->path);
90
+ return result;
91
+ }
92
+
93
+ return PM_STRING_INIT_SUCCESS;
94
+ }
95
+
96
+ /**
97
+ * Close the file handle and free the path.
98
+ */
99
+ static void
100
+ pm_string_file_handle_close(pm_string_file_handle_t *handle) {
101
+ xfree(handle->path);
102
+ CloseHandle(handle->file);
103
+ }
104
+ #endif
105
+
50
106
  /**
51
107
  * Read the file indicated by the filepath parameter into source and load its
52
108
  * contents and size into the given `pm_string_t`. The given `pm_string_t`
@@ -58,69 +114,66 @@ pm_string_constant_init(pm_string_t *string, const char *source, size_t length)
58
114
  * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
59
115
  * `mmap`, and on other POSIX systems we'll use `read`.
60
116
  */
61
- PRISM_EXPORTED_FUNCTION bool
117
+ PRISM_EXPORTED_FUNCTION pm_string_init_result_t
62
118
  pm_string_mapped_init(pm_string_t *string, const char *filepath) {
63
119
  #ifdef _WIN32
64
120
  // Open the file for reading.
65
- HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
66
-
67
- if (file == INVALID_HANDLE_VALUE) {
68
- return false;
69
- }
121
+ pm_string_file_handle_t handle;
122
+ pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
123
+ if (result != PM_STRING_INIT_SUCCESS) return result;
70
124
 
71
125
  // Get the file size.
72
- DWORD file_size = GetFileSize(file, NULL);
126
+ DWORD file_size = GetFileSize(handle.file, NULL);
73
127
  if (file_size == INVALID_FILE_SIZE) {
74
- CloseHandle(file);
75
- return false;
128
+ pm_string_file_handle_close(&handle);
129
+ return PM_STRING_INIT_ERROR_GENERIC;
76
130
  }
77
131
 
78
132
  // If the file is empty, then we don't need to do anything else, we'll set
79
133
  // the source to a constant empty string and return.
80
134
  if (file_size == 0) {
81
- CloseHandle(file);
135
+ pm_string_file_handle_close(&handle);
82
136
  const uint8_t source[] = "";
83
137
  *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
84
- return true;
138
+ return PM_STRING_INIT_SUCCESS;
85
139
  }
86
140
 
87
141
  // Create a mapping of the file.
88
- HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
142
+ HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
89
143
  if (mapping == NULL) {
90
- CloseHandle(file);
91
- return false;
144
+ pm_string_file_handle_close(&handle);
145
+ return PM_STRING_INIT_ERROR_GENERIC;
92
146
  }
93
147
 
94
148
  // Map the file into memory.
95
149
  uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
96
150
  CloseHandle(mapping);
97
- CloseHandle(file);
151
+ pm_string_file_handle_close(&handle);
98
152
 
99
153
  if (source == NULL) {
100
- return false;
154
+ return PM_STRING_INIT_ERROR_GENERIC;
101
155
  }
102
156
 
103
157
  *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
104
- return true;
158
+ return PM_STRING_INIT_SUCCESS;
105
159
  #elif defined(_POSIX_MAPPED_FILES)
106
160
  // Open the file for reading
107
161
  int fd = open(filepath, O_RDONLY);
108
162
  if (fd == -1) {
109
- return false;
163
+ return PM_STRING_INIT_ERROR_GENERIC;
110
164
  }
111
165
 
112
166
  // Stat the file to get the file size
113
167
  struct stat sb;
114
168
  if (fstat(fd, &sb) == -1) {
115
169
  close(fd);
116
- return false;
170
+ return PM_STRING_INIT_ERROR_GENERIC;
117
171
  }
118
172
 
119
173
  // Ensure it is a file and not a directory
120
174
  if (S_ISDIR(sb.st_mode)) {
121
- errno = EISDIR;
122
175
  close(fd);
123
- return false;
176
+ return PM_STRING_INIT_ERROR_DIRECTORY;
124
177
  }
125
178
 
126
179
  // mmap the file descriptor to virtually get the contents
@@ -131,17 +184,17 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
131
184
  close(fd);
132
185
  const uint8_t source[] = "";
133
186
  *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
134
- return true;
187
+ return PM_STRING_INIT_SUCCESS;
135
188
  }
136
189
 
137
190
  source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
138
191
  if (source == MAP_FAILED) {
139
- return false;
192
+ return PM_STRING_INIT_ERROR_GENERIC;
140
193
  }
141
194
 
142
195
  close(fd);
143
196
  *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
144
- return true;
197
+ return PM_STRING_INIT_SUCCESS;
145
198
  #else
146
199
  return pm_string_file_init(string, filepath);
147
200
  #endif
@@ -152,100 +205,105 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
152
205
  * contents and size into the given `pm_string_t`. The given `pm_string_t`
153
206
  * should be freed using `pm_string_free` when it is no longer used.
154
207
  */
155
- PRISM_EXPORTED_FUNCTION bool
208
+ PRISM_EXPORTED_FUNCTION pm_string_init_result_t
156
209
  pm_string_file_init(pm_string_t *string, const char *filepath) {
157
210
  #ifdef _WIN32
158
211
  // Open the file for reading.
159
- HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
160
-
161
- if (file == INVALID_HANDLE_VALUE) {
162
- return false;
163
- }
212
+ pm_string_file_handle_t handle;
213
+ pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
214
+ if (result != PM_STRING_INIT_SUCCESS) return result;
164
215
 
165
216
  // Get the file size.
166
- DWORD file_size = GetFileSize(file, NULL);
217
+ DWORD file_size = GetFileSize(handle.file, NULL);
167
218
  if (file_size == INVALID_FILE_SIZE) {
168
- CloseHandle(file);
169
- return false;
219
+ pm_string_file_handle_close(&handle);
220
+ return PM_STRING_INIT_ERROR_GENERIC;
170
221
  }
171
222
 
172
223
  // If the file is empty, then we don't need to do anything else, we'll set
173
224
  // the source to a constant empty string and return.
174
225
  if (file_size == 0) {
175
- CloseHandle(file);
226
+ pm_string_file_handle_close(&handle);
176
227
  const uint8_t source[] = "";
177
228
  *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
178
- return true;
229
+ return PM_STRING_INIT_SUCCESS;
179
230
  }
180
231
 
181
232
  // Create a buffer to read the file into.
182
233
  uint8_t *source = xmalloc(file_size);
183
234
  if (source == NULL) {
184
- CloseHandle(file);
185
- return false;
235
+ pm_string_file_handle_close(&handle);
236
+ return PM_STRING_INIT_ERROR_GENERIC;
186
237
  }
187
238
 
188
239
  // Read the contents of the file
189
240
  DWORD bytes_read;
190
- if (!ReadFile(file, source, file_size, &bytes_read, NULL)) {
191
- CloseHandle(file);
192
- return false;
241
+ if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
242
+ pm_string_file_handle_close(&handle);
243
+ return PM_STRING_INIT_ERROR_GENERIC;
193
244
  }
194
245
 
195
246
  // Check the number of bytes read
196
247
  if (bytes_read != file_size) {
197
248
  xfree(source);
198
- CloseHandle(file);
199
- return false;
249
+ pm_string_file_handle_close(&handle);
250
+ return PM_STRING_INIT_ERROR_GENERIC;
200
251
  }
201
252
 
202
- CloseHandle(file);
253
+ pm_string_file_handle_close(&handle);
203
254
  *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size };
204
- return true;
255
+ return PM_STRING_INIT_SUCCESS;
205
256
  #elif defined(PRISM_HAS_FILESYSTEM)
206
- FILE *file = fopen(filepath, "rb");
207
- if (file == NULL) {
208
- return false;
257
+ // Open the file for reading
258
+ int fd = open(filepath, O_RDONLY);
259
+ if (fd == -1) {
260
+ return PM_STRING_INIT_ERROR_GENERIC;
209
261
  }
210
262
 
211
- fseek(file, 0, SEEK_END);
212
- long file_size = ftell(file);
263
+ // Stat the file to get the file size
264
+ struct stat sb;
265
+ if (fstat(fd, &sb) == -1) {
266
+ close(fd);
267
+ return PM_STRING_INIT_ERROR_GENERIC;
268
+ }
213
269
 
214
- if (file_size == -1) {
215
- fclose(file);
216
- return false;
270
+ // Ensure it is a file and not a directory
271
+ if (S_ISDIR(sb.st_mode)) {
272
+ close(fd);
273
+ return PM_STRING_INIT_ERROR_DIRECTORY;
217
274
  }
218
275
 
219
- if (file_size == 0) {
220
- fclose(file);
276
+ // Check the size to see if it's empty
277
+ size_t size = (size_t) sb.st_size;
278
+ if (size == 0) {
279
+ close(fd);
221
280
  const uint8_t source[] = "";
222
281
  *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
223
- return true;
282
+ return PM_STRING_INIT_SUCCESS;
224
283
  }
225
284
 
226
- size_t length = (size_t) file_size;
285
+ size_t length = (size_t) size;
227
286
  uint8_t *source = xmalloc(length);
228
287
  if (source == NULL) {
229
- fclose(file);
230
- return false;
288
+ close(fd);
289
+ return PM_STRING_INIT_ERROR_GENERIC;
231
290
  }
232
291
 
233
- fseek(file, 0, SEEK_SET);
234
- size_t bytes_read = fread(source, length, 1, file);
235
- fclose(file);
292
+ long bytes_read = (long) read(fd, source, length);
293
+ close(fd);
236
294
 
237
- if (bytes_read != 1) {
295
+ if (bytes_read == -1) {
238
296
  xfree(source);
239
- return false;
297
+ return PM_STRING_INIT_ERROR_GENERIC;
240
298
  }
241
299
 
242
300
  *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
243
- return true;
301
+ return PM_STRING_INIT_SUCCESS;
244
302
  #else
245
303
  (void) string;
246
304
  (void) filepath;
247
305
  perror("pm_string_file_init is not implemented for this platform");
248
- return false;
306
+ return PM_STRING_INIT_ERROR_GENERIC;
249
307
  #endif
250
308
  }
251
309
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prism
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-28 00:00:00.000000000 Z
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -98,7 +98,6 @@ files:
98
98
  - lib/prism/translation/parser.rb
99
99
  - lib/prism/translation/parser/compiler.rb
100
100
  - lib/prism/translation/parser/lexer.rb
101
- - lib/prism/translation/parser/rubocop.rb
102
101
  - lib/prism/translation/parser33.rb
103
102
  - lib/prism/translation/parser34.rb
104
103
  - lib/prism/translation/ripper.rb
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
- # typed: ignore
3
-
4
- warn "WARN: Prism is directly supported since RuboCop 1.62. The `prism/translation/parser/rubocop` file is deprecated."
5
-
6
- require "parser"
7
- require "rubocop"
8
-
9
- require_relative "../../prism"
10
- require_relative "../parser"
11
-
12
- module Prism
13
- module Translation
14
- class Parser
15
- # This is the special version numbers that should be used in RuboCop
16
- # configuration files to trigger using prism.
17
-
18
- # For Ruby 3.3
19
- VERSION_3_3 = 80_82_73_83_77.33
20
-
21
- # For Ruby 3.4
22
- VERSION_3_4 = 80_82_73_83_77.34
23
-
24
- # This module gets prepended into RuboCop::AST::ProcessedSource.
25
- module ProcessedSource
26
- # This condition is compatible with rubocop-ast versions up to 1.30.0.
27
- if RuboCop::AST::ProcessedSource.instance_method(:parser_class).arity == 1
28
- # Redefine parser_class so that we can inject the prism parser into the
29
- # list of known parsers.
30
- def parser_class(ruby_version)
31
- if ruby_version == Prism::Translation::Parser::VERSION_3_3
32
- warn "WARN: Setting `TargetRubyVersion: 80_82_73_83_77.33` is deprecated. " \
33
- "Set to `ParserEngine: parser_prism` and `TargetRubyVersion: 3.3` instead."
34
- require_relative "../parser33"
35
- Prism::Translation::Parser33
36
- elsif ruby_version == Prism::Translation::Parser::VERSION_3_4
37
- warn "WARN: Setting `TargetRubyVersion: 80_82_73_83_77.34` is deprecated. " \
38
- "Set to `ParserEngine: parser_prism` and `TargetRubyVersion: 3.4` instead."
39
- require_relative "../parser34"
40
- Prism::Translation::Parser34
41
- else
42
- super
43
- end
44
- end
45
- else
46
- # Redefine parser_class so that we can inject the prism parser into the
47
- # list of known parsers.
48
- def parser_class(ruby_version, _parser_engine)
49
- if ruby_version == Prism::Translation::Parser::VERSION_3_3
50
- warn "WARN: Setting `TargetRubyVersion: 80_82_73_83_77.33` is deprecated. " \
51
- "Set to `ParserEngine: parser_prism` and `TargetRubyVersion: 3.3` instead."
52
- require_relative "../parser33"
53
- Prism::Translation::Parser33
54
- elsif ruby_version == Prism::Translation::Parser::VERSION_3_4
55
- warn "WARN: Setting `TargetRubyVersion: 80_82_73_83_77.34` is deprecated. " \
56
- "Set to `ParserEngine: parser_prism` and `TargetRubyVersion: 3.4` instead."
57
- require_relative "../parser34"
58
- Prism::Translation::Parser34
59
- else
60
- super
61
- end
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
68
-
69
- # :stopdoc:
70
- RuboCop::AST::ProcessedSource.prepend(Prism::Translation::Parser::ProcessedSource)
71
- known_rubies = RuboCop::TargetRuby.const_get(:KNOWN_RUBIES)
72
- RuboCop::TargetRuby.send(:remove_const, :KNOWN_RUBIES)
73
- RuboCop::TargetRuby::KNOWN_RUBIES = [*known_rubies, Prism::Translation::Parser::VERSION_3_3].freeze