ruston 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.ruby-version +1 -0
- data/Cargo.lock +398 -0
- data/Cargo.toml +12 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/lex.rs +11 -0
- data/examples/parser.rs +30 -0
- data/examples/rb/parsejson.rb +14 -0
- data/examples/ruby_run.rs +23 -0
- data/lib/ruston/version.rb +3 -0
- data/lib/ruston.rb +7 -0
- data/ruston.gemspec +25 -0
- data/src/json.rs +379 -0
- data/src/lib.rs +81 -0
- data/src/ruby.rs +78 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cf5c0f1352fca5ac06d4941ed73e96eaf9f7094e2cc87e48ac731224e9756850
|
4
|
+
data.tar.gz: 7774865e19f036dc54fcd0f087ff8dff7af7ee3a291f04f7a541796ace67a8d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8ba536beb1a1b3a18af9061ab073622edee3222161281a3146e18d28eda1872fe404371891cc45f82dea28c89ceb6172ceac4b0d29e55da3b69b23cf400b134
|
7
|
+
data.tar.gz: 263de613a6e15a1179fc2ab3e9e4d877c0266ffa8ed3da1ae697b0b9f251ac214fd7b6adb527e344618a95f7c382dc609491367b059bbf63e2e417edf65c1d36
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.1.1
|
data/Cargo.lock
ADDED
@@ -0,0 +1,398 @@
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
2
|
+
# It is not intended for manual editing.
|
3
|
+
version = 3
|
4
|
+
|
5
|
+
[[package]]
|
6
|
+
name = "aho-corasick"
|
7
|
+
version = "0.7.18"
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
9
|
+
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
10
|
+
dependencies = [
|
11
|
+
"memchr",
|
12
|
+
]
|
13
|
+
|
14
|
+
[[package]]
|
15
|
+
name = "ansi_term"
|
16
|
+
version = "0.12.1"
|
17
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
18
|
+
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
19
|
+
dependencies = [
|
20
|
+
"winapi",
|
21
|
+
]
|
22
|
+
|
23
|
+
[[package]]
|
24
|
+
name = "atty"
|
25
|
+
version = "0.2.14"
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
27
|
+
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
28
|
+
dependencies = [
|
29
|
+
"hermit-abi",
|
30
|
+
"libc",
|
31
|
+
"winapi",
|
32
|
+
]
|
33
|
+
|
34
|
+
[[package]]
|
35
|
+
name = "bindgen"
|
36
|
+
version = "0.59.2"
|
37
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
38
|
+
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
|
39
|
+
dependencies = [
|
40
|
+
"bitflags",
|
41
|
+
"cexpr",
|
42
|
+
"clang-sys",
|
43
|
+
"clap",
|
44
|
+
"env_logger",
|
45
|
+
"lazy_static",
|
46
|
+
"lazycell",
|
47
|
+
"log",
|
48
|
+
"peeking_take_while",
|
49
|
+
"proc-macro2",
|
50
|
+
"quote",
|
51
|
+
"regex",
|
52
|
+
"rustc-hash",
|
53
|
+
"shlex",
|
54
|
+
"which",
|
55
|
+
]
|
56
|
+
|
57
|
+
[[package]]
|
58
|
+
name = "bitflags"
|
59
|
+
version = "1.3.2"
|
60
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
61
|
+
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
62
|
+
|
63
|
+
[[package]]
|
64
|
+
name = "cc"
|
65
|
+
version = "1.0.73"
|
66
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
67
|
+
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
68
|
+
|
69
|
+
[[package]]
|
70
|
+
name = "cexpr"
|
71
|
+
version = "0.6.0"
|
72
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
73
|
+
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
74
|
+
dependencies = [
|
75
|
+
"nom",
|
76
|
+
]
|
77
|
+
|
78
|
+
[[package]]
|
79
|
+
name = "cfg-if"
|
80
|
+
version = "1.0.0"
|
81
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
82
|
+
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
83
|
+
|
84
|
+
[[package]]
|
85
|
+
name = "clang-sys"
|
86
|
+
version = "1.3.3"
|
87
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
88
|
+
checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b"
|
89
|
+
dependencies = [
|
90
|
+
"glob",
|
91
|
+
"libc",
|
92
|
+
"libloading",
|
93
|
+
]
|
94
|
+
|
95
|
+
[[package]]
|
96
|
+
name = "clap"
|
97
|
+
version = "2.34.0"
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
99
|
+
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
100
|
+
dependencies = [
|
101
|
+
"ansi_term",
|
102
|
+
"atty",
|
103
|
+
"bitflags",
|
104
|
+
"strsim",
|
105
|
+
"textwrap",
|
106
|
+
"unicode-width",
|
107
|
+
"vec_map",
|
108
|
+
]
|
109
|
+
|
110
|
+
[[package]]
|
111
|
+
name = "coffret"
|
112
|
+
version = "0.0.3"
|
113
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
114
|
+
checksum = "efb0b42fe7c89fec1939af9293f94403f32bab4ac86769dbd8362d34c40e649c"
|
115
|
+
dependencies = [
|
116
|
+
"libc",
|
117
|
+
"rb-sys",
|
118
|
+
]
|
119
|
+
|
120
|
+
[[package]]
|
121
|
+
name = "either"
|
122
|
+
version = "1.6.1"
|
123
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
124
|
+
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
125
|
+
|
126
|
+
[[package]]
|
127
|
+
name = "env_logger"
|
128
|
+
version = "0.9.0"
|
129
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
130
|
+
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
131
|
+
dependencies = [
|
132
|
+
"atty",
|
133
|
+
"humantime",
|
134
|
+
"log",
|
135
|
+
"regex",
|
136
|
+
"termcolor",
|
137
|
+
]
|
138
|
+
|
139
|
+
[[package]]
|
140
|
+
name = "glob"
|
141
|
+
version = "0.3.0"
|
142
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
143
|
+
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
144
|
+
|
145
|
+
[[package]]
|
146
|
+
name = "hermit-abi"
|
147
|
+
version = "0.1.19"
|
148
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
149
|
+
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
150
|
+
dependencies = [
|
151
|
+
"libc",
|
152
|
+
]
|
153
|
+
|
154
|
+
[[package]]
|
155
|
+
name = "humantime"
|
156
|
+
version = "2.1.0"
|
157
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
158
|
+
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
159
|
+
|
160
|
+
[[package]]
|
161
|
+
name = "lazy_static"
|
162
|
+
version = "1.4.0"
|
163
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
164
|
+
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
165
|
+
|
166
|
+
[[package]]
|
167
|
+
name = "lazycell"
|
168
|
+
version = "1.3.0"
|
169
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
170
|
+
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
171
|
+
|
172
|
+
[[package]]
|
173
|
+
name = "libc"
|
174
|
+
version = "0.2.126"
|
175
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
176
|
+
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
177
|
+
|
178
|
+
[[package]]
|
179
|
+
name = "libloading"
|
180
|
+
version = "0.7.3"
|
181
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
182
|
+
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
183
|
+
dependencies = [
|
184
|
+
"cfg-if",
|
185
|
+
"winapi",
|
186
|
+
]
|
187
|
+
|
188
|
+
[[package]]
|
189
|
+
name = "linkify"
|
190
|
+
version = "0.8.1"
|
191
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
192
|
+
checksum = "28d9967eb7d0bc31c39c6f52e8fce42991c0cd1f7a2078326f0b7a399a584c8d"
|
193
|
+
dependencies = [
|
194
|
+
"memchr",
|
195
|
+
]
|
196
|
+
|
197
|
+
[[package]]
|
198
|
+
name = "log"
|
199
|
+
version = "0.4.17"
|
200
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
201
|
+
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
202
|
+
dependencies = [
|
203
|
+
"cfg-if",
|
204
|
+
]
|
205
|
+
|
206
|
+
[[package]]
|
207
|
+
name = "memchr"
|
208
|
+
version = "2.5.0"
|
209
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
210
|
+
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
211
|
+
|
212
|
+
[[package]]
|
213
|
+
name = "minimal-lexical"
|
214
|
+
version = "0.2.1"
|
215
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
216
|
+
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
217
|
+
|
218
|
+
[[package]]
|
219
|
+
name = "nom"
|
220
|
+
version = "7.1.1"
|
221
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
222
|
+
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
223
|
+
dependencies = [
|
224
|
+
"memchr",
|
225
|
+
"minimal-lexical",
|
226
|
+
]
|
227
|
+
|
228
|
+
[[package]]
|
229
|
+
name = "peeking_take_while"
|
230
|
+
version = "0.1.2"
|
231
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
232
|
+
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
233
|
+
|
234
|
+
[[package]]
|
235
|
+
name = "pkg-config"
|
236
|
+
version = "0.3.25"
|
237
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
238
|
+
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
239
|
+
|
240
|
+
[[package]]
|
241
|
+
name = "proc-macro2"
|
242
|
+
version = "1.0.39"
|
243
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
244
|
+
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
245
|
+
dependencies = [
|
246
|
+
"unicode-ident",
|
247
|
+
]
|
248
|
+
|
249
|
+
[[package]]
|
250
|
+
name = "quote"
|
251
|
+
version = "1.0.18"
|
252
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
253
|
+
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
254
|
+
dependencies = [
|
255
|
+
"proc-macro2",
|
256
|
+
]
|
257
|
+
|
258
|
+
[[package]]
|
259
|
+
name = "rb-sys"
|
260
|
+
version = "0.9.4"
|
261
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
262
|
+
checksum = "f5465c5bd695ef70959b91b4ca9cfd515e9af012f6d9f0ae46f09fa4bcc3b722"
|
263
|
+
dependencies = [
|
264
|
+
"bindgen",
|
265
|
+
"cc",
|
266
|
+
"lazy_static",
|
267
|
+
"linkify",
|
268
|
+
"pkg-config",
|
269
|
+
"shell-words",
|
270
|
+
]
|
271
|
+
|
272
|
+
[[package]]
|
273
|
+
name = "regex"
|
274
|
+
version = "1.5.6"
|
275
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
276
|
+
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
277
|
+
dependencies = [
|
278
|
+
"aho-corasick",
|
279
|
+
"memchr",
|
280
|
+
"regex-syntax",
|
281
|
+
]
|
282
|
+
|
283
|
+
[[package]]
|
284
|
+
name = "regex-syntax"
|
285
|
+
version = "0.6.26"
|
286
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
287
|
+
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
288
|
+
|
289
|
+
[[package]]
|
290
|
+
name = "rustc-hash"
|
291
|
+
version = "1.1.0"
|
292
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
293
|
+
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
294
|
+
|
295
|
+
[[package]]
|
296
|
+
name = "ruston"
|
297
|
+
version = "0.1.0"
|
298
|
+
dependencies = [
|
299
|
+
"coffret",
|
300
|
+
"libc",
|
301
|
+
"rb-sys",
|
302
|
+
]
|
303
|
+
|
304
|
+
[[package]]
|
305
|
+
name = "shell-words"
|
306
|
+
version = "1.1.0"
|
307
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
308
|
+
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
309
|
+
|
310
|
+
[[package]]
|
311
|
+
name = "shlex"
|
312
|
+
version = "1.1.0"
|
313
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
314
|
+
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
315
|
+
|
316
|
+
[[package]]
|
317
|
+
name = "strsim"
|
318
|
+
version = "0.8.0"
|
319
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
320
|
+
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
321
|
+
|
322
|
+
[[package]]
|
323
|
+
name = "termcolor"
|
324
|
+
version = "1.1.3"
|
325
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
326
|
+
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
327
|
+
dependencies = [
|
328
|
+
"winapi-util",
|
329
|
+
]
|
330
|
+
|
331
|
+
[[package]]
|
332
|
+
name = "textwrap"
|
333
|
+
version = "0.11.0"
|
334
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
335
|
+
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
336
|
+
dependencies = [
|
337
|
+
"unicode-width",
|
338
|
+
]
|
339
|
+
|
340
|
+
[[package]]
|
341
|
+
name = "unicode-ident"
|
342
|
+
version = "1.0.1"
|
343
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
344
|
+
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
345
|
+
|
346
|
+
[[package]]
|
347
|
+
name = "unicode-width"
|
348
|
+
version = "0.1.9"
|
349
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
350
|
+
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
351
|
+
|
352
|
+
[[package]]
|
353
|
+
name = "vec_map"
|
354
|
+
version = "0.8.2"
|
355
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
356
|
+
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
357
|
+
|
358
|
+
[[package]]
|
359
|
+
name = "which"
|
360
|
+
version = "4.2.5"
|
361
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
362
|
+
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
|
363
|
+
dependencies = [
|
364
|
+
"either",
|
365
|
+
"lazy_static",
|
366
|
+
"libc",
|
367
|
+
]
|
368
|
+
|
369
|
+
[[package]]
|
370
|
+
name = "winapi"
|
371
|
+
version = "0.3.9"
|
372
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
373
|
+
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
374
|
+
dependencies = [
|
375
|
+
"winapi-i686-pc-windows-gnu",
|
376
|
+
"winapi-x86_64-pc-windows-gnu",
|
377
|
+
]
|
378
|
+
|
379
|
+
[[package]]
|
380
|
+
name = "winapi-i686-pc-windows-gnu"
|
381
|
+
version = "0.4.0"
|
382
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
383
|
+
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
384
|
+
|
385
|
+
[[package]]
|
386
|
+
name = "winapi-util"
|
387
|
+
version = "0.1.5"
|
388
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
389
|
+
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
390
|
+
dependencies = [
|
391
|
+
"winapi",
|
392
|
+
]
|
393
|
+
|
394
|
+
[[package]]
|
395
|
+
name = "winapi-x86_64-pc-windows-gnu"
|
396
|
+
version = "0.4.0"
|
397
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
398
|
+
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
data/Cargo.toml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruston (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
rake (13.0.6)
|
10
|
+
|
11
|
+
PLATFORMS
|
12
|
+
arm64-darwin-21
|
13
|
+
|
14
|
+
DEPENDENCIES
|
15
|
+
bundler (>= 1.17)
|
16
|
+
rake (>= 10.0)
|
17
|
+
ruston!
|
18
|
+
|
19
|
+
BUNDLED WITH
|
20
|
+
2.4.0.dev
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Uchio Kondo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Ruston
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruston`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'ruston'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install ruston
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/udzura/ruston.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ruston"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/examples/lex.rs
ADDED
data/examples/parser.rs
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
extern crate ruston;
|
2
|
+
|
3
|
+
fn main() {
|
4
|
+
let ret = ruston::json::parse("true");
|
5
|
+
dbg!(ret);
|
6
|
+
|
7
|
+
let ret = ruston::json::parse("123");
|
8
|
+
dbg!(ret);
|
9
|
+
|
10
|
+
let ret = ruston::json::parse("\"Hola\"");
|
11
|
+
dbg!(ret);
|
12
|
+
|
13
|
+
let ret = ruston::json::parse("[1, 2, 3, false]");
|
14
|
+
dbg!(ret);
|
15
|
+
|
16
|
+
let ret = ruston::json::parse("{\"foo\": true, \"bar\": 123}");
|
17
|
+
dbg!(ret);
|
18
|
+
|
19
|
+
let nested = "
|
20
|
+
{
|
21
|
+
\"id\": 1,
|
22
|
+
\"user\": {
|
23
|
+
\"name\": \"Akubi\",
|
24
|
+
\"age\": 3,
|
25
|
+
}
|
26
|
+
}
|
27
|
+
";
|
28
|
+
let ret = ruston::json::parse(nested);
|
29
|
+
dbg!(ret);
|
30
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
extern crate ruston;
|
2
|
+
|
3
|
+
fn main() {
|
4
|
+
// let json = "
|
5
|
+
// {\"Hello\": true, \"world\": [1, 2, 3]}
|
6
|
+
// ";
|
7
|
+
|
8
|
+
let json = "true";
|
9
|
+
let ruby = ruston::ruby::parse_into_ruby(json.to_string()).unwrap();
|
10
|
+
unsafe { rb::rb_p(ruby) };
|
11
|
+
|
12
|
+
let json = "\"Rubyist?\"";
|
13
|
+
let ruby = ruston::ruby::parse_into_ruby(json.to_string()).unwrap();
|
14
|
+
unsafe { rb::rb_p(ruby) };
|
15
|
+
|
16
|
+
let json = "[\"Rubyist?\", 12, null]";
|
17
|
+
let ruby = ruston::ruby::parse_into_ruby(json.to_string()).unwrap();
|
18
|
+
unsafe { rb::rb_p(ruby) };
|
19
|
+
|
20
|
+
let json = "{\"Rubyist?\": true}";
|
21
|
+
let ruby = ruston::ruby::parse_into_ruby(json.to_string()).unwrap();
|
22
|
+
unsafe { rb::rb_p(ruby) };
|
23
|
+
}
|
data/lib/ruston.rb
ADDED
data/ruston.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "ruston/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ruston"
|
7
|
+
spec.version = Ruston::VERSION
|
8
|
+
spec.authors = ["Uchio Kondo"]
|
9
|
+
spec.email = ["udzura@udzura.jp"]
|
10
|
+
|
11
|
+
spec.summary = %q{Sample Rust-made gem to parse simple JSON...}
|
12
|
+
spec.description = %q{Sample Rust-made gem to parse simple JSON...}
|
13
|
+
spec.homepage = "https://github.com/udzura/ruston"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
# spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
spec.extensions = ["Cargo.toml"]
|
25
|
+
end
|
data/src/json.rs
ADDED
@@ -0,0 +1,379 @@
|
|
1
|
+
use std::{collections::HashMap, fmt::Display, hash::Hash};
|
2
|
+
|
3
|
+
#[derive(Debug, Clone)]
|
4
|
+
pub struct Token {
|
5
|
+
pub start: usize,
|
6
|
+
pub end: usize,
|
7
|
+
pub lexeme: String,
|
8
|
+
pub ty: TokenType,
|
9
|
+
}
|
10
|
+
|
11
|
+
impl Token {
|
12
|
+
fn is(&self, ty: TokenType) -> bool {
|
13
|
+
self.ty == ty
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
18
|
+
pub enum TokenType {
|
19
|
+
BraceOpen,
|
20
|
+
BraceClose,
|
21
|
+
BracketOpen,
|
22
|
+
BracketClose,
|
23
|
+
Colon,
|
24
|
+
Comma,
|
25
|
+
Number,
|
26
|
+
StrLit,
|
27
|
+
Null,
|
28
|
+
True,
|
29
|
+
False,
|
30
|
+
|
31
|
+
EoF,
|
32
|
+
}
|
33
|
+
|
34
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
35
|
+
pub enum Value {
|
36
|
+
Null,
|
37
|
+
True,
|
38
|
+
False,
|
39
|
+
Int(i32),
|
40
|
+
Str(String),
|
41
|
+
Array(Vec<Value>),
|
42
|
+
Object(usize, HashMap<Value, Value>),
|
43
|
+
}
|
44
|
+
|
45
|
+
impl Hash for Value {
|
46
|
+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
47
|
+
match self {
|
48
|
+
Self::Object(val, _) => val.hash(state),
|
49
|
+
_ => core::mem::discriminant(self).hash(state),
|
50
|
+
};
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
#[derive(Debug, Clone)]
|
55
|
+
pub struct JsonError {
|
56
|
+
pub message: String,
|
57
|
+
}
|
58
|
+
|
59
|
+
impl JsonError {
|
60
|
+
pub fn raise(message: impl Into<String>) -> Self {
|
61
|
+
Self {
|
62
|
+
message: message.into(),
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
impl Display for JsonError {
|
68
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
69
|
+
write!(f, "{}", &self.message)
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
impl std::error::Error for JsonError {}
|
74
|
+
|
75
|
+
pub mod lexer {
|
76
|
+
use super::*;
|
77
|
+
|
78
|
+
#[derive(Debug, Default)]
|
79
|
+
pub struct Lex {
|
80
|
+
pub stream: String,
|
81
|
+
pub start: usize,
|
82
|
+
pub current: usize,
|
83
|
+
pub line: usize,
|
84
|
+
|
85
|
+
pub tokens: Vec<Token>,
|
86
|
+
}
|
87
|
+
|
88
|
+
impl Lex {
|
89
|
+
pub fn run(stream: String) -> Result<Self, JsonError> {
|
90
|
+
let mut lex = Self {
|
91
|
+
stream,
|
92
|
+
..Default::default()
|
93
|
+
};
|
94
|
+
|
95
|
+
lex.process()?;
|
96
|
+
Ok(lex)
|
97
|
+
}
|
98
|
+
|
99
|
+
fn process(&mut self) -> Result<(), JsonError> {
|
100
|
+
loop {
|
101
|
+
match self.advance()? {
|
102
|
+
'{' => self.push_token(TokenType::BraceOpen),
|
103
|
+
'}' => self.push_token(TokenType::BraceClose),
|
104
|
+
'[' => self.push_token(TokenType::BracketOpen),
|
105
|
+
']' => self.push_token(TokenType::BracketClose),
|
106
|
+
':' => self.push_token(TokenType::Colon),
|
107
|
+
',' => self.push_token(TokenType::Comma),
|
108
|
+
't' => {
|
109
|
+
self.matches("rue")?;
|
110
|
+
self.push_token(TokenType::True)
|
111
|
+
}
|
112
|
+
'f' => {
|
113
|
+
self.matches("alse")?;
|
114
|
+
self.push_token(TokenType::False)
|
115
|
+
}
|
116
|
+
'n' => {
|
117
|
+
self.matches("ull")?;
|
118
|
+
self.push_token(TokenType::Null)
|
119
|
+
}
|
120
|
+
'"' => loop {
|
121
|
+
let c = self
|
122
|
+
.advance()
|
123
|
+
.or_else(|_| Err(JsonError::raise("quote unmet")))?;
|
124
|
+
if c == '"' {
|
125
|
+
self.push_token(TokenType::StrLit);
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
},
|
129
|
+
'\n' => {
|
130
|
+
self.line += 1;
|
131
|
+
self.start = self.current
|
132
|
+
}
|
133
|
+
' ' | '\t' => self.start = self.current,
|
134
|
+
'1'..='9' => {
|
135
|
+
while is_digit(self.peek()) {
|
136
|
+
self.advance()?;
|
137
|
+
}
|
138
|
+
self.push_token(TokenType::Number);
|
139
|
+
}
|
140
|
+
c => return Err(JsonError::raise(format!("unexpected token {}", c))),
|
141
|
+
}
|
142
|
+
if self.reached_end() {
|
143
|
+
self.push_token(TokenType::EoF);
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
Ok(())
|
148
|
+
}
|
149
|
+
|
150
|
+
fn peek(&mut self) -> Option<char> {
|
151
|
+
self.stream
|
152
|
+
.chars()
|
153
|
+
.collect::<Vec<char>>()
|
154
|
+
.get(self.current)
|
155
|
+
.map(|c| *c)
|
156
|
+
}
|
157
|
+
|
158
|
+
fn matches(&mut self, s: &str) -> Result<(), JsonError> {
|
159
|
+
for c in s.chars() {
|
160
|
+
let c2 = self.advance()?;
|
161
|
+
if c2 != c {
|
162
|
+
return Err(JsonError::raise(format!("unexpected character {}", c2)));
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
Ok(())
|
167
|
+
}
|
168
|
+
|
169
|
+
fn advance(&mut self) -> Result<char, JsonError> {
|
170
|
+
let c = self.peek().ok_or_else(|| JsonError::raise("EoF"))?;
|
171
|
+
// eprintln!("process: {}", c);
|
172
|
+
self.current += 1;
|
173
|
+
Ok(c)
|
174
|
+
}
|
175
|
+
|
176
|
+
fn reached_end(&mut self) -> bool {
|
177
|
+
self.current >= self.stream.len()
|
178
|
+
}
|
179
|
+
|
180
|
+
fn push_token(&mut self, ty: TokenType) {
|
181
|
+
let token = Token {
|
182
|
+
start: self.start,
|
183
|
+
end: self.current,
|
184
|
+
lexeme: (&self.stream[self.start..self.current]).to_string(),
|
185
|
+
ty,
|
186
|
+
};
|
187
|
+
|
188
|
+
// eprintln!("pusing: {:?}: {}", &token.ty, &token.lexeme);
|
189
|
+
self.tokens.push(token);
|
190
|
+
self.start = self.current
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
fn is_digit(c: Option<char>) -> bool {
|
195
|
+
match c {
|
196
|
+
Some(c) => c >= '0' && c <= '9',
|
197
|
+
None => false,
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
pub mod parser {
|
203
|
+
use super::*;
|
204
|
+
|
205
|
+
#[derive(Debug)]
|
206
|
+
pub struct Parser {
|
207
|
+
pub stream: Vec<Token>,
|
208
|
+
pub current: usize,
|
209
|
+
pub value: Value,
|
210
|
+
|
211
|
+
next_object_id: usize,
|
212
|
+
}
|
213
|
+
|
214
|
+
impl Parser {
|
215
|
+
pub fn run(stream: Vec<Token>) -> Result<Self, JsonError> {
|
216
|
+
let mut parser = Self {
|
217
|
+
stream,
|
218
|
+
current: 0,
|
219
|
+
value: Value::Null,
|
220
|
+
next_object_id: (1 << 16),
|
221
|
+
};
|
222
|
+
|
223
|
+
parser.process()?;
|
224
|
+
Ok(parser)
|
225
|
+
}
|
226
|
+
|
227
|
+
fn process(&mut self) -> Result<(), JsonError> {
|
228
|
+
self.value = self.process_value()?;
|
229
|
+
|
230
|
+
if !self.reached_end()? {
|
231
|
+
return Err(JsonError::raise("JSON has continued form"));
|
232
|
+
}
|
233
|
+
|
234
|
+
Ok(())
|
235
|
+
}
|
236
|
+
|
237
|
+
fn process_value(&mut self) -> Result<Value, JsonError> {
|
238
|
+
use TokenType::*;
|
239
|
+
let token = self.succ(1)?;
|
240
|
+
let value = match &token.ty {
|
241
|
+
Null => Value::Null,
|
242
|
+
True => Value::True,
|
243
|
+
False => Value::False,
|
244
|
+
Number => Value::Int(token.lexeme.parse().unwrap()),
|
245
|
+
StrLit => {
|
246
|
+
let len = token.lexeme.len();
|
247
|
+
Value::Str((&token.lexeme[1..(len - 1)]).to_string())
|
248
|
+
}
|
249
|
+
BracketOpen => self.array()?,
|
250
|
+
BraceOpen => self.object()?,
|
251
|
+
|
252
|
+
t => {
|
253
|
+
todo!("Unexpected token: {:?}", &t)
|
254
|
+
}
|
255
|
+
};
|
256
|
+
Ok(value)
|
257
|
+
}
|
258
|
+
|
259
|
+
fn array(&mut self) -> Result<Value, JsonError> {
|
260
|
+
use TokenType::*;
|
261
|
+
let mut ar = Vec::new();
|
262
|
+
loop {
|
263
|
+
match self.peek(0) {
|
264
|
+
Some(t) => match &t.ty {
|
265
|
+
EoF => return Err(JsonError::raise("EoF")),
|
266
|
+
BracketClose => {
|
267
|
+
self.succ(1)?;
|
268
|
+
break;
|
269
|
+
}
|
270
|
+
_ => {
|
271
|
+
let v = self.process_value()?;
|
272
|
+
ar.push(v);
|
273
|
+
match self.peek(0) {
|
274
|
+
None => return Err(JsonError::raise("EoF")),
|
275
|
+
Some(t) => {
|
276
|
+
if t.is(Comma) {
|
277
|
+
self.succ(1)?;
|
278
|
+
let n = self.peek(0);
|
279
|
+
if n.is_none() {
|
280
|
+
return Err(JsonError::raise("EoF"));
|
281
|
+
}
|
282
|
+
if n.unwrap().is(BracketClose) {
|
283
|
+
return Err(JsonError::raise("Unexpected ]"));
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
289
|
+
},
|
290
|
+
None => return Err(JsonError::raise("EoF")),
|
291
|
+
}
|
292
|
+
}
|
293
|
+
Ok(Value::Array(ar))
|
294
|
+
}
|
295
|
+
|
296
|
+
fn object(&mut self) -> Result<Value, JsonError> {
|
297
|
+
use TokenType::*;
|
298
|
+
let mut ha = HashMap::new();
|
299
|
+
loop {
|
300
|
+
match self.peek(0) {
|
301
|
+
Some(t) => match &t.ty {
|
302
|
+
EoF => return Err(JsonError::raise("EoF")),
|
303
|
+
BraceClose => {
|
304
|
+
self.succ(1)?;
|
305
|
+
break;
|
306
|
+
}
|
307
|
+
_ => {
|
308
|
+
let k = self.process_value()?;
|
309
|
+
match self.peek(0) {
|
310
|
+
None => return Err(JsonError::raise("EoF")),
|
311
|
+
Some(t) => {
|
312
|
+
if t.is(Colon) {
|
313
|
+
self.succ(1)?;
|
314
|
+
} else {
|
315
|
+
return Err(JsonError::raise(format!(
|
316
|
+
"Unexpected token {:?}",
|
317
|
+
t.ty
|
318
|
+
)));
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
let v = self.process_value()?;
|
323
|
+
ha.insert(k, v);
|
324
|
+
match self.peek(0) {
|
325
|
+
None => return Err(JsonError::raise("EoF")),
|
326
|
+
Some(t) => match t.ty {
|
327
|
+
BraceClose => {
|
328
|
+
continue;
|
329
|
+
}
|
330
|
+
Comma => {
|
331
|
+
self.succ(1)?;
|
332
|
+
continue;
|
333
|
+
}
|
334
|
+
other => {
|
335
|
+
return Err(JsonError::raise(format!(
|
336
|
+
"Unexpected token {:?}",
|
337
|
+
other
|
338
|
+
)));
|
339
|
+
}
|
340
|
+
},
|
341
|
+
}
|
342
|
+
}
|
343
|
+
},
|
344
|
+
None => return Err(JsonError::raise("EoF")),
|
345
|
+
}
|
346
|
+
}
|
347
|
+
self.next_object_id += 1;
|
348
|
+
Ok(Value::Object(self.next_object_id, ha))
|
349
|
+
}
|
350
|
+
|
351
|
+
fn peek(&mut self, count: usize) -> Option<&Token> {
|
352
|
+
self.stream.get(self.current + count)
|
353
|
+
}
|
354
|
+
|
355
|
+
fn previous(&mut self) -> Option<&Token> {
|
356
|
+
if self.current == 0 {
|
357
|
+
return None;
|
358
|
+
}
|
359
|
+
self.stream.get(self.current - 1)
|
360
|
+
}
|
361
|
+
|
362
|
+
fn succ(&mut self, count: usize) -> Result<&Token, JsonError> {
|
363
|
+
self.current += count;
|
364
|
+
self.previous().ok_or_else(|| JsonError::raise("EoF"))
|
365
|
+
}
|
366
|
+
|
367
|
+
fn reached_end(&mut self) -> Result<bool, JsonError> {
|
368
|
+
self.peek(0)
|
369
|
+
.map(|tok| tok.is(TokenType::EoF))
|
370
|
+
.ok_or_else(|| JsonError::raise("EoF"))
|
371
|
+
}
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
pub fn parse(json: impl Into<String>) -> Value {
|
376
|
+
let tokens = self::lexer::Lex::run(json.into()).unwrap().tokens;
|
377
|
+
let value = self::parser::Parser::run(tokens).unwrap().value;
|
378
|
+
value
|
379
|
+
}
|
data/src/lib.rs
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
pub mod json;
|
2
|
+
pub mod ruby;
|
3
|
+
|
4
|
+
use std::slice;
|
5
|
+
|
6
|
+
use coffret::*;
|
7
|
+
use rb_sys::*;
|
8
|
+
|
9
|
+
pub struct RubyFn {
|
10
|
+
value: unsafe extern "C" fn() -> RubyValue,
|
11
|
+
}
|
12
|
+
|
13
|
+
impl From<RubyFn> for unsafe extern "C" fn() -> RubyValue {
|
14
|
+
fn from(from: RubyFn) -> Self {
|
15
|
+
from.value
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
impl From<unsafe extern "C" fn() -> RubyValue> for RubyFn {
|
20
|
+
fn from(from: unsafe extern "C" fn() -> RubyValue) -> Self {
|
21
|
+
RubyFn { value: from }
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
impl From<unsafe extern "C" fn(RubyValue) -> RubyValue> for RubyFn {
|
26
|
+
fn from(from: unsafe extern "C" fn(RubyValue) -> RubyValue) -> Self {
|
27
|
+
let value = unsafe {
|
28
|
+
std::mem::transmute::<
|
29
|
+
unsafe extern "C" fn(RubyValue) -> RubyValue,
|
30
|
+
unsafe extern "C" fn() -> RubyValue,
|
31
|
+
>(from)
|
32
|
+
};
|
33
|
+
RubyFn { value }
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
impl From<unsafe extern "C" fn(RubyValue, RubyValue) -> RubyValue> for RubyFn {
|
38
|
+
fn from(from: unsafe extern "C" fn(RubyValue, RubyValue) -> RubyValue) -> Self {
|
39
|
+
let value = unsafe {
|
40
|
+
std::mem::transmute::<
|
41
|
+
unsafe extern "C" fn(RubyValue, RubyValue) -> RubyValue,
|
42
|
+
unsafe extern "C" fn() -> RubyValue,
|
43
|
+
>(from)
|
44
|
+
};
|
45
|
+
RubyFn { value }
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
#[no_mangle]
|
50
|
+
pub unsafe extern "C" fn ruston_parse(_slf: RubyValue, json: RubyValue) -> RubyValue {
|
51
|
+
let mut json = Box::new(json);
|
52
|
+
let data: *const u8 = unsafe { rb_string_value_ptr(json.as_mut()) } as *const u8;
|
53
|
+
let len = unsafe { macros::RSTRING_LEN(json.as_ref().clone()) };
|
54
|
+
|
55
|
+
let bytes: &[u8] = unsafe { slice::from_raw_parts(data, len as usize) };
|
56
|
+
let json = String::from_utf8_lossy(bytes);
|
57
|
+
|
58
|
+
crate::ruby::parse_into_ruby(json.to_string()).unwrap()
|
59
|
+
}
|
60
|
+
|
61
|
+
fn init_ruston_internal() -> Result<(), Box<dyn std::error::Error>> {
|
62
|
+
println!("Rust loaded");
|
63
|
+
|
64
|
+
let object = class::object_class();
|
65
|
+
let klass = class::define_class("Ruston", object);
|
66
|
+
|
67
|
+
let callback: RubyFn = (ruston_parse as unsafe extern "C" fn(u64, u64) -> u64).into();
|
68
|
+
|
69
|
+
class::define_method(klass, "parse", callback.into(), 1);
|
70
|
+
|
71
|
+
Ok(())
|
72
|
+
}
|
73
|
+
|
74
|
+
#[allow(non_snake_case)]
|
75
|
+
#[no_mangle]
|
76
|
+
pub extern "C" fn Init_ruston() {
|
77
|
+
match init_ruston_internal() {
|
78
|
+
Err(e) => exception::rustly_raise(e.as_ref()),
|
79
|
+
Ok(_) => {}
|
80
|
+
}
|
81
|
+
}
|
data/src/ruby.rs
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
use crate::json;
|
2
|
+
|
3
|
+
use rb::RubyValue;
|
4
|
+
use rb_sys as rb;
|
5
|
+
|
6
|
+
mod v {
|
7
|
+
use rb_sys::*;
|
8
|
+
|
9
|
+
#[repr(C)]
|
10
|
+
pub struct WrappedRubyValue {
|
11
|
+
value: u32,
|
12
|
+
padding: u32,
|
13
|
+
}
|
14
|
+
|
15
|
+
impl From<WrappedRubyValue> for RubyValue {
|
16
|
+
fn from(from: WrappedRubyValue) -> Self {
|
17
|
+
let v = unsafe { std::mem::transmute::<WrappedRubyValue, RubyValue>(from) };
|
18
|
+
v
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
#[allow(non_upper_case_globals)]
|
23
|
+
pub const True: WrappedRubyValue = WrappedRubyValue {
|
24
|
+
value: ruby_special_consts::RUBY_Qtrue as u32,
|
25
|
+
padding: 0,
|
26
|
+
};
|
27
|
+
|
28
|
+
#[allow(non_upper_case_globals)]
|
29
|
+
pub const False: WrappedRubyValue = WrappedRubyValue {
|
30
|
+
value: ruby_special_consts::RUBY_Qfalse as u32,
|
31
|
+
padding: 0,
|
32
|
+
};
|
33
|
+
|
34
|
+
#[allow(non_upper_case_globals)]
|
35
|
+
pub const Nil: WrappedRubyValue = WrappedRubyValue {
|
36
|
+
value: ruby_special_consts::RUBY_Qnil as u32,
|
37
|
+
padding: 0,
|
38
|
+
};
|
39
|
+
}
|
40
|
+
|
41
|
+
pub fn parse_into_ruby(json: String) -> Result<rb::RubyValue, Box<dyn std::error::Error>> {
|
42
|
+
unsafe { rb::ruby_init() };
|
43
|
+
|
44
|
+
let value = json::parse(json);
|
45
|
+
let ruby = walk(&value);
|
46
|
+
Ok(ruby)
|
47
|
+
}
|
48
|
+
|
49
|
+
fn walk(value: &json::Value) -> rb::RubyValue {
|
50
|
+
use json::Value::*;
|
51
|
+
match value {
|
52
|
+
Null => v::Nil.into(),
|
53
|
+
True => v::True.into(),
|
54
|
+
False => v::False.into(),
|
55
|
+
Int(i) => unsafe { rb::rb_int2big(*i as isize) },
|
56
|
+
Str(s) => unsafe {
|
57
|
+
let s = format!("{}\0", s);
|
58
|
+
rb::rb_utf8_str_new_cstr(s.as_ptr() as *const i8)
|
59
|
+
},
|
60
|
+
Array(v) => unsafe {
|
61
|
+
let ary = rb::rb_ary_new_capa(v.len() as i64);
|
62
|
+
for e in v.iter() {
|
63
|
+
let en = walk(e);
|
64
|
+
rb::rb_ary_push(ary, en);
|
65
|
+
}
|
66
|
+
ary
|
67
|
+
},
|
68
|
+
Object(_, ha) => unsafe {
|
69
|
+
let hash = rb::rb_hash_new();
|
70
|
+
for (k, v) in ha.iter() {
|
71
|
+
let rk = walk(k);
|
72
|
+
let rv = walk(v);
|
73
|
+
rb::rb_hash_aset(hash, rk, rv);
|
74
|
+
}
|
75
|
+
hash
|
76
|
+
},
|
77
|
+
}
|
78
|
+
}
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruston
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Uchio Kondo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-06-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Sample Rust-made gem to parse simple JSON...
|
14
|
+
email:
|
15
|
+
- udzura@udzura.jp
|
16
|
+
executables: []
|
17
|
+
extensions:
|
18
|
+
- Cargo.toml
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- ".gitignore"
|
22
|
+
- ".ruby-version"
|
23
|
+
- Cargo.lock
|
24
|
+
- Cargo.toml
|
25
|
+
- Gemfile
|
26
|
+
- Gemfile.lock
|
27
|
+
- LICENSE.txt
|
28
|
+
- README.md
|
29
|
+
- Rakefile
|
30
|
+
- bin/console
|
31
|
+
- bin/setup
|
32
|
+
- examples/lex.rs
|
33
|
+
- examples/parser.rs
|
34
|
+
- examples/rb/parsejson.rb
|
35
|
+
- examples/ruby_run.rs
|
36
|
+
- lib/ruston.rb
|
37
|
+
- lib/ruston/version.rb
|
38
|
+
- ruston.gemspec
|
39
|
+
- src/json.rs
|
40
|
+
- src/lib.rs
|
41
|
+
- src/ruby.rs
|
42
|
+
homepage: https://github.com/udzura/ruston
|
43
|
+
licenses:
|
44
|
+
- MIT
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubygems_version: 3.4.0.dev
|
62
|
+
signing_key:
|
63
|
+
specification_version: 4
|
64
|
+
summary: Sample Rust-made gem to parse simple JSON...
|
65
|
+
test_files: []
|