prism 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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