edn_turbo 0.5.7 → 0.7.1
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 +5 -5
- data/.dir-locals.el +3 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +53 -0
- data/LICENSE +1 -1
- data/README.md +18 -24
- data/Rakefile +22 -27
- data/docker/Dockerfile +40 -0
- data/docker/build +11 -0
- data/docker/common.sh +28 -0
- data/docker/console +11 -0
- data/docker/docker-compose.yml +22 -0
- data/docker/entrypoint +3 -0
- data/docker/make-check +8 -0
- data/docker/run +9 -0
- data/ext/edn_turbo/edn_parser.cc +1206 -1026
- data/ext/edn_turbo/edn_parser.rl +913 -842
- data/ext/edn_turbo/extconf.rb +36 -1
- data/ext/edn_turbo/main.cc +201 -166
- data/ext/edn_turbo/parser.h +105 -76
- data/ext/edn_turbo/parser_def.cc +204 -182
- data/ext/edn_turbo/util.cc +250 -220
- data/ext/edn_turbo/util.h +55 -26
- data/ext/edn_turbo/util_unicode.cc +41 -19
- data/ext/edn_turbo/util_unicode.h +29 -7
- data/lib/edn_turbo.rb +34 -0
- data/lib/edn_turbo/edn_parser.rb +22 -0
- data/lib/edn_turbo/version.rb +24 -2
- data/spec/edn_turbo/edn_parser_spec.rb +419 -0
- data/spec/spec_helper.rb +96 -0
- metadata +65 -15
- data/test/test_output_diff.rb +0 -408
data/ext/edn_turbo/edn_parser.rl
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
// The MIT License (MIT)
|
2
|
+
|
3
|
+
// Copyright (c) 2015-2021 Ed Porras
|
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.
|
22
|
+
|
1
23
|
#include <iostream>
|
2
24
|
#include <string>
|
3
25
|
#include <sstream>
|
@@ -19,43 +41,43 @@
|
|
19
41
|
//
|
20
42
|
|
21
43
|
%%{
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
44
|
+
machine EDN_common;
|
45
|
+
|
46
|
+
cr = '\n';
|
47
|
+
counter = ( cr @{ line_number++; } );
|
48
|
+
cr_neg = [^\n];
|
49
|
+
ws = [\t\v\f\r ] | ',' | counter;
|
50
|
+
comment = ';' cr_neg* counter;
|
51
|
+
ignore = ws | comment;
|
52
|
+
|
53
|
+
operators = [/\.\*!_\?$%&<>\=+\-\'];
|
54
|
+
|
55
|
+
begin_dispatch = '#';
|
56
|
+
begin_keyword = ':';
|
57
|
+
begin_char = '\\';
|
58
|
+
begin_vector = '[';
|
59
|
+
begin_map = '{';
|
60
|
+
begin_list = '(';
|
61
|
+
begin_meta = '^';
|
62
|
+
string_delim = '"';
|
63
|
+
begin_number = digit;
|
64
|
+
begin_value = alnum | [:\"\{\[\(\\\#^] | operators;
|
65
|
+
begin_symbol = alpha;
|
66
|
+
|
67
|
+
# int / decimal rules
|
68
|
+
integer = ('0' | [1-9] digit*);
|
69
|
+
exp = ([Ee] [+\-]? digit+);
|
70
|
+
|
71
|
+
|
72
|
+
# common actions
|
73
|
+
action close_err {
|
74
|
+
std::stringstream s;
|
75
|
+
s << "unterminated " << EDN_TYPE;
|
76
|
+
error(__FUNCTION__, s.str());
|
77
|
+
fhold; fbreak;
|
78
|
+
}
|
79
|
+
|
80
|
+
action exit { fhold; fbreak; }
|
59
81
|
}%%
|
60
82
|
|
61
83
|
// ============================================================
|
@@ -63,135 +85,140 @@
|
|
63
85
|
//
|
64
86
|
|
65
87
|
%%{
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
88
|
+
machine EDN_value;
|
89
|
+
include EDN_common;
|
90
|
+
|
91
|
+
write data;
|
92
|
+
|
93
|
+
action parse_val_string {
|
94
|
+
// string types within double-quotes
|
95
|
+
const char *np = parse_string(fpc, pe, v);
|
96
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
97
|
+
}
|
98
|
+
|
99
|
+
action parse_val_keyword {
|
100
|
+
// tokens with a leading ':'
|
101
|
+
const char *np = parse_keyword(fpc, pe, v);
|
102
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
103
|
+
}
|
104
|
+
|
105
|
+
action parse_val_number {
|
106
|
+
// tokens w/ leading digits: non-negative integers & decimals.
|
107
|
+
// try to parse a decimal first
|
108
|
+
const char *np = parse_decimal(fpc, pe, v);
|
109
|
+
if (np == nullptr) {
|
110
|
+
// if we can't, try to parse it as a ratio
|
111
|
+
np = parse_ratio(fpc, pe, v);
|
112
|
+
|
113
|
+
// otherwise, an int
|
114
|
+
if (np == nullptr) {
|
89
115
|
np = parse_integer(fpc, pe, v);
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
if (np) {
|
120
|
+
fexec np;
|
121
|
+
fhold;
|
122
|
+
fbreak;
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
error(__FUNCTION__, "number format error", *p);
|
126
|
+
fexec pe;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
action parse_val_operator {
|
131
|
+
// stand-alone operators *, +, -, etc.
|
132
|
+
const char *np = parse_operator(fpc, pe, v);
|
133
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
134
|
+
}
|
135
|
+
|
136
|
+
action parse_val_char {
|
137
|
+
// tokens w/ leading \ (escaped characters \newline, \c, etc.)
|
138
|
+
const char *np = parse_esc_char(fpc, pe, v);
|
139
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
140
|
+
}
|
141
|
+
|
142
|
+
action parse_val_symbol {
|
143
|
+
// user identifiers and reserved keywords (true, false, nil)
|
144
|
+
VALUE sym = Qnil;
|
145
|
+
const char *np = parse_symbol(fpc, pe, sym);
|
146
|
+
if (np == nullptr) { fexec pe; } else {
|
147
|
+
// parse_symbol will make 'sym' a ruby string
|
148
|
+
if (std::strcmp(RSTRING_PTR(sym), "true") == 0) { v = Qtrue; }
|
149
|
+
else if (std::strcmp(RSTRING_PTR(sym), "false") == 0) { v = Qfalse; }
|
150
|
+
else if (std::strcmp(RSTRING_PTR(sym), "nil") == 0) { v = Qnil; }
|
151
|
+
else {
|
152
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SYMBOL_METHOD, sym);
|
153
|
+
}
|
154
|
+
fexec np;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
action parse_val_vector {
|
159
|
+
// [
|
160
|
+
const char *np = parse_vector(fpc, pe, v);
|
161
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
162
|
+
}
|
163
|
+
|
164
|
+
action parse_val_list {
|
165
|
+
// (
|
166
|
+
const char *np = parse_list(fpc, pe, v);
|
167
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
168
|
+
}
|
169
|
+
|
170
|
+
action parse_val_map {
|
171
|
+
// {
|
172
|
+
const char *np = parse_map(fpc, pe, v);
|
173
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
174
|
+
}
|
175
|
+
|
176
|
+
action parse_val_meta {
|
177
|
+
// ^
|
178
|
+
const char *np = parse_meta(fpc, pe);
|
179
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
180
|
+
}
|
181
|
+
|
182
|
+
action parse_val_dispatch {
|
183
|
+
// handles tokens w/ leading # ("#_", "#{", and tagged elems)
|
184
|
+
const char *np = parse_dispatch(fpc + 1, pe, v);
|
185
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
186
|
+
}
|
187
|
+
|
188
|
+
|
189
|
+
main := (
|
190
|
+
string_delim >parse_val_string |
|
191
|
+
begin_keyword >parse_val_keyword |
|
192
|
+
begin_number >parse_val_number |
|
193
|
+
operators >parse_val_operator |
|
194
|
+
begin_char >parse_val_char |
|
195
|
+
begin_symbol >parse_val_symbol |
|
196
|
+
begin_vector >parse_val_vector |
|
197
|
+
begin_list >parse_val_list |
|
198
|
+
begin_map >parse_val_map |
|
199
|
+
begin_meta >parse_val_meta |
|
200
|
+
begin_dispatch >parse_val_dispatch
|
201
|
+
) %*exit;
|
175
202
|
}%%
|
176
203
|
|
177
204
|
|
178
205
|
const char *edn::Parser::parse_value(const char *p, const char *pe, VALUE& v)
|
179
206
|
{
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
207
|
+
// std::cerr << __FUNCTION__ << "() p: \"" << p << "\"" << std::endl;
|
208
|
+
int cs;
|
209
|
+
|
210
|
+
%% write init;
|
211
|
+
%% write exec;
|
212
|
+
|
213
|
+
if (cs >= EDN_value_first_final) {
|
214
|
+
return p;
|
215
|
+
}
|
216
|
+
else if (cs == EDN_value_error) {
|
217
|
+
error(__FUNCTION__, "token error", *p);
|
218
|
+
return pe;
|
219
|
+
}
|
220
|
+
else if (cs == EDN_value_en_main) {} // silence ragel warning
|
221
|
+
return nullptr;
|
195
222
|
}
|
196
223
|
|
197
224
|
|
@@ -203,51 +230,51 @@ const char *edn::Parser::parse_value(const char *p, const char *pe, VALUE& v)
|
|
203
230
|
// ascii range is found.
|
204
231
|
//
|
205
232
|
%%{
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
233
|
+
machine EDN_string;
|
234
|
+
include EDN_common;
|
235
|
+
|
236
|
+
write data;
|
237
|
+
|
238
|
+
action parse_chars {
|
239
|
+
if (edn::util::parse_byte_stream(p_save + 1, p, v, encode)) {
|
240
|
+
fexec p + 1;
|
241
|
+
} else {
|
242
|
+
fhold; fbreak;
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
action mark_for_encoding {
|
247
|
+
encode = true;
|
248
|
+
}
|
249
|
+
|
250
|
+
main := string_delim (
|
251
|
+
(^([\"\\] | 0xc2..0xf5) |
|
252
|
+
((0xc2..0xf5) |
|
253
|
+
'\\'[\"\\/bfnrt] |
|
254
|
+
'\\u'[0-9a-fA-F]{4}) $mark_for_encoding |
|
255
|
+
'\\'^([\"\\/bfnrtu]))* %parse_chars
|
256
|
+
) :>> string_delim @err(close_err) @exit;
|
230
257
|
}%%
|
231
258
|
|
232
259
|
|
233
260
|
const char* edn::Parser::parse_string(const char *p, const char *pe, VALUE& v)
|
234
261
|
{
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
262
|
+
static const char* EDN_TYPE = "string";
|
263
|
+
int cs;
|
264
|
+
bool encode = false;
|
265
|
+
|
266
|
+
%% write init;
|
267
|
+
const char* p_save = p;
|
268
|
+
%% write exec;
|
269
|
+
|
270
|
+
if (cs >= EDN_string_first_final) {
|
271
|
+
return p + 1;
|
272
|
+
}
|
273
|
+
else if (cs == EDN_string_error) {
|
274
|
+
return pe;
|
275
|
+
}
|
276
|
+
else if (cs == EDN_string_en_main) {} // silence ragel warning
|
277
|
+
return nullptr;
|
251
278
|
}
|
252
279
|
|
253
280
|
|
@@ -256,79 +283,78 @@ const char* edn::Parser::parse_string(const char *p, const char *pe, VALUE& v)
|
|
256
283
|
// keyword parsing
|
257
284
|
//
|
258
285
|
%%{
|
259
|
-
|
260
|
-
|
286
|
+
machine EDN_keyword;
|
287
|
+
include EDN_common;
|
261
288
|
|
262
|
-
|
263
|
-
|
289
|
+
keyword_start = alpha | [\.\*!_\?$%&<>\=+\-\'\#];
|
290
|
+
keyword_chars = (keyword_start | digit | ':');
|
264
291
|
|
265
|
-
|
266
|
-
|
292
|
+
keyword_name = keyword_start keyword_chars*;
|
293
|
+
keyword = keyword_name ('/' keyword_chars*)?;
|
267
294
|
|
268
|
-
|
295
|
+
write data;
|
269
296
|
|
270
297
|
|
271
|
-
|
298
|
+
main := begin_keyword keyword (^(keyword_chars | '/')? @exit);
|
272
299
|
}%%
|
273
300
|
|
274
301
|
|
275
302
|
const char* edn::Parser::parse_keyword(const char *p, const char *pe, VALUE& v)
|
276
303
|
{
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
304
|
+
int cs;
|
305
|
+
|
306
|
+
%% write init;
|
307
|
+
const char* p_save = p;
|
308
|
+
%% write exec;
|
309
|
+
|
310
|
+
if (cs >= EDN_keyword_first_final) {
|
311
|
+
std::string buf;
|
312
|
+
uintmax_t len = p - p_save;
|
313
|
+
// don't include leading ':' because the ruby symbol will handle it
|
314
|
+
buf.append(p_save + 1, len - 1);
|
315
|
+
v = ID2SYM(rb_intern(buf.c_str()));
|
316
|
+
return p;
|
317
|
+
}
|
318
|
+
else if (cs == EDN_keyword_error) {
|
319
|
+
error(__FUNCTION__, "invalid keyword", *p);
|
320
|
+
return pe;
|
321
|
+
}
|
322
|
+
else if (cs == EDN_keyword_en_main) {} // silence ragel warning
|
323
|
+
return nullptr;
|
297
324
|
}
|
298
325
|
|
299
326
|
|
300
|
-
|
301
327
|
// ============================================================
|
302
328
|
// decimal parsing machine
|
303
329
|
//
|
304
330
|
%%{
|
305
|
-
|
306
|
-
|
331
|
+
machine EDN_decimal;
|
332
|
+
include EDN_common;
|
307
333
|
|
308
|
-
|
334
|
+
write data noerror;
|
309
335
|
|
310
336
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
337
|
+
main := ('-'|'+')? (
|
338
|
+
(integer '.' digit* (exp? [M]?)) |
|
339
|
+
(integer exp)
|
340
|
+
) (^[0-9Ee.+\-M]? @exit );
|
315
341
|
}%%
|
316
342
|
|
317
343
|
|
318
344
|
const char* edn::Parser::parse_decimal(const char *p, const char *pe, VALUE& v)
|
319
345
|
{
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
346
|
+
int cs;
|
347
|
+
|
348
|
+
%% write init;
|
349
|
+
const char* p_save = p;
|
350
|
+
%% write exec;
|
351
|
+
|
352
|
+
if (cs >= EDN_decimal_first_final) {
|
353
|
+
v = edn::util::float_to_ruby(p_save, p - p_save);
|
354
|
+
return p + 1;
|
355
|
+
}
|
356
|
+
else if (cs == EDN_decimal_en_main) {} // silence ragel warning
|
357
|
+
return nullptr;
|
332
358
|
}
|
333
359
|
|
334
360
|
|
@@ -336,34 +362,65 @@ const char* edn::Parser::parse_decimal(const char *p, const char *pe, VALUE& v)
|
|
336
362
|
// integer parsing machine - M suffix will return a BigNum
|
337
363
|
//
|
338
364
|
%%{
|
339
|
-
|
340
|
-
|
365
|
+
machine EDN_integer;
|
366
|
+
include EDN_common;
|
341
367
|
|
342
|
-
|
368
|
+
write data noerror;
|
343
369
|
|
344
370
|
|
345
|
-
|
346
|
-
|
347
|
-
|
371
|
+
main := (
|
372
|
+
('-'|'+')? (integer [MN]?)
|
373
|
+
) (^[0-9MN+\-]? @exit);
|
348
374
|
}%%
|
349
375
|
|
350
376
|
const char* edn::Parser::parse_integer(const char *p, const char *pe, VALUE& v)
|
351
377
|
{
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
378
|
+
int cs;
|
379
|
+
|
380
|
+
%% write init;
|
381
|
+
const char* p_save = p;
|
382
|
+
%% write exec;
|
383
|
+
|
384
|
+
if (cs >= EDN_integer_first_final) {
|
385
|
+
v = edn::util::integer_to_ruby(p_save, p - p_save);
|
386
|
+
return p + 1;
|
387
|
+
}
|
388
|
+
else if (cs == EDN_integer_en_main) {} // silence ragel warning
|
389
|
+
return nullptr;
|
364
390
|
}
|
365
391
|
|
366
392
|
|
393
|
+
// ============================================================
|
394
|
+
// ratio parsing machine
|
395
|
+
//
|
396
|
+
%%{
|
397
|
+
machine EDN_ratio;
|
398
|
+
include EDN_common;
|
399
|
+
|
400
|
+
write data noerror;
|
401
|
+
|
402
|
+
|
403
|
+
main := (
|
404
|
+
('-'|'+')? (integer '/' integer)
|
405
|
+
) (^[0-9+\-\/]? @exit);
|
406
|
+
}%%
|
407
|
+
|
408
|
+
|
409
|
+
const char* edn::Parser::parse_ratio(const char *p, const char *pe, VALUE& v)
|
410
|
+
{
|
411
|
+
int cs;
|
412
|
+
|
413
|
+
%% write init;
|
414
|
+
const char* p_save = p;
|
415
|
+
%% write exec;
|
416
|
+
|
417
|
+
if (cs >= EDN_ratio_first_final) {
|
418
|
+
v = edn::util::ratio_to_ruby(p_save, p - p_save);
|
419
|
+
return p + 1;
|
420
|
+
}
|
421
|
+
else if (cs == EDN_ratio_en_main) {} // silence ragel warning
|
422
|
+
return nullptr;
|
423
|
+
}
|
367
424
|
|
368
425
|
// ============================================================
|
369
426
|
// operator parsing - handles tokens w/ a leading operator:
|
@@ -373,81 +430,86 @@ const char* edn::Parser::parse_integer(const char *p, const char *pe, VALUE& v)
|
|
373
430
|
// 3. stand-alone operators: +, -, /, *, etc.
|
374
431
|
//
|
375
432
|
%%{
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
433
|
+
machine EDN_operator;
|
434
|
+
include EDN_common;
|
435
|
+
|
436
|
+
write data;
|
437
|
+
|
438
|
+
action parse_op_symbol {
|
439
|
+
// parse a symbol including the leading operator (-, +, .)
|
440
|
+
VALUE sym = Qnil;
|
441
|
+
const char *np = parse_symbol(p_save, pe, sym);
|
442
|
+
if (np == nullptr) { fexec pe; } else {
|
443
|
+
if (sym != Qnil)
|
444
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SYMBOL_METHOD, sym);
|
445
|
+
fexec np;
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
action parse_op_number {
|
450
|
+
// parse a number with the leading symbol - this is slightly
|
451
|
+
// different than the one within EDN_value since it includes
|
452
|
+
// the leading - or +
|
453
|
+
//
|
454
|
+
// try to parse a decimal first
|
455
|
+
const char *np = parse_decimal(p_save, pe, v);
|
456
|
+
if (np == nullptr) {
|
457
|
+
// if we can't, try to parse it as a ratio
|
458
|
+
np = parse_ratio(p_save, pe, v);
|
459
|
+
|
460
|
+
if (np == nullptr) {
|
461
|
+
// again, if we can't, try to parse it as an int
|
401
462
|
np = parse_integer(p_save, pe, v);
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
463
|
+
}
|
464
|
+
}
|
465
|
+
|
466
|
+
if (np) {
|
467
|
+
fexec np;
|
468
|
+
fhold;
|
469
|
+
fbreak;
|
470
|
+
}
|
471
|
+
else {
|
472
|
+
error(__FUNCTION__, "number format error", *p);
|
473
|
+
fexec pe;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
action parse_op {
|
478
|
+
// stand-alone operators (-, +, /, ... etc)
|
479
|
+
char op[2] = { *p_save, 0 };
|
480
|
+
VALUE sym = rb_str_new2(op);
|
481
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SYMBOL_METHOD, sym);
|
482
|
+
}
|
483
|
+
|
484
|
+
valid_non_numeric_chars = alpha|operators|':'|'#';
|
485
|
+
valid_chars = valid_non_numeric_chars | digit;
|
486
|
+
|
487
|
+
main := (
|
488
|
+
('-'|'+') begin_number >parse_op_number |
|
489
|
+
(operators - [\-\+\.]) valid_chars >parse_op_symbol |
|
490
|
+
[\-\+\.] valid_non_numeric_chars valid_chars* >parse_op_symbol |
|
491
|
+
operators ignore* >parse_op
|
492
|
+
) ^(valid_chars)? @exit;
|
431
493
|
}%%
|
432
494
|
|
433
495
|
|
434
496
|
const char* edn::Parser::parse_operator(const char *p, const char *pe, VALUE& v)
|
435
497
|
{
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
498
|
+
int cs;
|
499
|
+
|
500
|
+
%% write init;
|
501
|
+
const char* p_save = p;
|
502
|
+
%% write exec;
|
503
|
+
|
504
|
+
if (cs >= EDN_operator_first_final) {
|
505
|
+
return p;
|
506
|
+
}
|
507
|
+
else if (cs == EDN_operator_error) {
|
508
|
+
error(__FUNCTION__, "symbol syntax error", *p);
|
509
|
+
return pe;
|
510
|
+
}
|
511
|
+
else if (cs == EDN_operator_en_main) {} // silence ragel warning
|
512
|
+
return nullptr;
|
451
513
|
}
|
452
514
|
|
453
515
|
|
@@ -456,47 +518,46 @@ const char* edn::Parser::parse_operator(const char *p, const char *pe, VALUE& v)
|
|
456
518
|
// escaped char parsing - handles \c, \newline, \formfeed, etc.
|
457
519
|
//
|
458
520
|
%%{
|
459
|
-
|
460
|
-
|
521
|
+
machine EDN_escaped_char;
|
522
|
+
include EDN_common;
|
461
523
|
|
462
|
-
|
524
|
+
write data;
|
463
525
|
|
464
|
-
|
526
|
+
valid_chars = extend;
|
465
527
|
|
466
528
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
529
|
+
main := begin_char (
|
530
|
+
'space' | 'newline' | 'tab' | 'return' | 'formfeed' | 'backspace' |
|
531
|
+
valid_chars
|
532
|
+
) (ignore* | [\\\]\}\)])? @exit;
|
471
533
|
}%%
|
472
534
|
|
473
535
|
|
474
536
|
const char* edn::Parser::parse_esc_char(const char *p, const char *pe, VALUE& v)
|
475
537
|
{
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
538
|
+
int cs;
|
539
|
+
|
540
|
+
%% write init;
|
541
|
+
const char* p_save = p;
|
542
|
+
%% write exec;
|
543
|
+
|
544
|
+
if (cs >= EDN_escaped_char_first_final) {
|
545
|
+
// convert the escaped value to a character
|
546
|
+
if (!edn::util::parse_escaped_char(p_save + 1, p, v)) {
|
547
|
+
return pe;
|
548
|
+
}
|
549
|
+
return p;
|
550
|
+
}
|
551
|
+
else if (cs == EDN_escaped_char_error) {
|
552
|
+
error(__FUNCTION__, "unexpected value", *p);
|
553
|
+
return pe;
|
554
|
+
}
|
555
|
+
else if (cs == EDN_escaped_char_en_main) {} // silence ragel warning
|
556
|
+
return nullptr;
|
495
557
|
}
|
496
558
|
|
497
559
|
|
498
560
|
|
499
|
-
|
500
561
|
// ============================================================
|
501
562
|
// symbol parsing - handles identifiers that begin with an alpha
|
502
563
|
// character and an optional leading operator (name, -today,
|
@@ -504,58 +565,57 @@ const char* edn::Parser::parse_esc_char(const char *p, const char *pe, VALUE& v)
|
|
504
565
|
//
|
505
566
|
//
|
506
567
|
%%{
|
507
|
-
|
508
|
-
|
568
|
+
machine EDN_symbol;
|
569
|
+
include EDN_common;
|
509
570
|
|
510
|
-
|
571
|
+
write data;
|
511
572
|
|
512
|
-
|
513
|
-
|
514
|
-
|
573
|
+
symbol_ops_1 = [\.\-\+];
|
574
|
+
symbol_ops_2 = [\*!_\?$%&<>\=\'];
|
575
|
+
symbol_ops_3 = [:\#];
|
515
576
|
|
516
|
-
|
577
|
+
symbol_start = alpha | symbol_ops_1 | symbol_ops_2;
|
517
578
|
|
518
|
-
|
579
|
+
symbol_chars = symbol_start | digit | symbol_ops_3;
|
519
580
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
581
|
+
symbol_name = (
|
582
|
+
(alpha symbol_chars*) |
|
583
|
+
(symbol_ops_1 (symbol_start | symbol_ops_3) symbol_chars*) |
|
584
|
+
(symbol_start symbol_chars+) |
|
585
|
+
operators{1}
|
586
|
+
);
|
587
|
+
symbol = '/' | (symbol_name ('/' symbol_name)?);
|
527
588
|
|
528
589
|
|
529
|
-
|
530
|
-
|
531
|
-
|
590
|
+
main := (
|
591
|
+
symbol
|
592
|
+
) ignore* (^(symbol_chars | '/')? @exit);
|
532
593
|
}%%
|
533
594
|
|
534
595
|
|
535
596
|
const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
536
597
|
{
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
598
|
+
int cs;
|
599
|
+
|
600
|
+
%% write init;
|
601
|
+
const char* p_save = p;
|
602
|
+
%% write exec;
|
603
|
+
|
604
|
+
if (cs >= EDN_symbol_first_final) {
|
605
|
+
// copy the symbol text
|
606
|
+
if (s == Qnil)
|
607
|
+
s = rb_str_new2("");
|
608
|
+
rb_str_cat(s, p_save, p - p_save);
|
609
|
+
return p;
|
610
|
+
}
|
611
|
+
else if (cs == EDN_symbol_error) {
|
612
|
+
error(__FUNCTION__, "invalid symbol sequence", *p);
|
613
|
+
}
|
614
|
+
else if (cs == EDN_symbol_en_main) {} // silence ragel warning
|
615
|
+
return nullptr;
|
555
616
|
}
|
556
617
|
|
557
618
|
|
558
|
-
|
559
619
|
// ============================================================
|
560
620
|
// EDN_sequence_common is used to parse EDN containers - elements are
|
561
621
|
// initially stored in an array and then the final corresponding
|
@@ -563,75 +623,75 @@ const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
|
563
623
|
// sets the same array is used)
|
564
624
|
//
|
565
625
|
%%{
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
626
|
+
machine EDN_sequence_common;
|
627
|
+
include EDN_common;
|
628
|
+
|
629
|
+
action open_seq {
|
630
|
+
// sequences store elements in an array, then process it to
|
631
|
+
// convert it to a list, set, or map as needed once the
|
632
|
+
// sequence end is reached
|
633
|
+
elems = rb_ary_new();
|
634
|
+
// additionally, metadata for elements in the sequence may be
|
635
|
+
// carried so we must push a new level in the metadata stack
|
636
|
+
new_meta_list();
|
637
|
+
}
|
638
|
+
|
639
|
+
action close_seq {
|
640
|
+
// remove the current metadata level
|
641
|
+
del_top_meta_list();
|
642
|
+
}
|
643
|
+
|
644
|
+
action parse_item {
|
645
|
+
// reads an item within a sequence (vector, list, map, or
|
646
|
+
// set). Regardless of the sequence type, an array of the
|
647
|
+
// items is built. Once done, the sequence parser will convert
|
648
|
+
// if needed
|
649
|
+
VALUE e;
|
650
|
+
std::size_t meta_sz = meta_size();
|
651
|
+
const char *np = parse_value(fpc, pe, e);
|
652
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
653
|
+
// if there's an entry in the discard list, the current
|
654
|
+
// object is not meant to be kept due to a #_ so don't
|
655
|
+
// push it into the list of elements
|
656
|
+
if (!discard.empty()) {
|
657
|
+
discard.pop_back();
|
658
|
+
}
|
659
|
+
else if (!meta_empty()) {
|
660
|
+
// check if parse_value added metadata
|
661
|
+
if (meta_size() == meta_sz) {
|
662
|
+
// there's metadata and it didn't increase so
|
663
|
+
// parse_value() read an element we care
|
664
|
+
// about. Bind the metadata to it and add it to
|
665
|
+
// the sequence
|
666
|
+
e = edn::util::call_module_fn(rb_mEDNT, EDNT_EXTENDED_VALUE_METHOD, e, ruby_meta());
|
667
|
+
rb_ary_push(elems, e);
|
598
668
|
}
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
// no metadata.. just push it
|
611
|
-
rb_ary_push(elems, e);
|
612
|
-
}
|
613
|
-
fexec np;
|
614
|
-
}
|
615
|
-
}
|
616
|
-
|
617
|
-
element = begin_value >parse_item;
|
618
|
-
next_element = ignore* element;
|
619
|
-
sequence = ((element ignore*) (next_element ignore*)*);
|
669
|
+
} else {
|
670
|
+
// no metadata.. just push it
|
671
|
+
rb_ary_push(elems, e);
|
672
|
+
}
|
673
|
+
fexec np;
|
674
|
+
}
|
675
|
+
}
|
676
|
+
|
677
|
+
element = begin_value >parse_item;
|
678
|
+
next_element = ignore* element;
|
679
|
+
sequence = ((element ignore*) (next_element ignore*)*);
|
620
680
|
}%%
|
621
681
|
|
622
682
|
//
|
623
683
|
// vector-specific machine
|
624
684
|
%%{
|
625
|
-
|
626
|
-
|
685
|
+
machine EDN_vector;
|
686
|
+
include EDN_sequence_common;
|
627
687
|
|
628
|
-
|
688
|
+
end_vector = ']';
|
629
689
|
|
630
|
-
|
690
|
+
write data;
|
631
691
|
|
632
|
-
|
633
|
-
|
634
|
-
|
692
|
+
main := begin_vector @open_seq (
|
693
|
+
ignore* sequence? :>> end_vector @close_seq
|
694
|
+
) @err(close_err) @exit;
|
635
695
|
}%%
|
636
696
|
|
637
697
|
|
@@ -640,24 +700,24 @@ const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
|
640
700
|
//
|
641
701
|
const char* edn::Parser::parse_vector(const char *p, const char *pe, VALUE& v)
|
642
702
|
{
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
703
|
+
static const char* EDN_TYPE = "vector";
|
704
|
+
|
705
|
+
int cs;
|
706
|
+
VALUE elems; // will store the vector's elements - allocated in @open_seq
|
707
|
+
|
708
|
+
%% write init;
|
709
|
+
%% write exec;
|
710
|
+
|
711
|
+
if (cs >= EDN_vector_first_final) {
|
712
|
+
v = elems;
|
713
|
+
return p + 1;
|
714
|
+
}
|
715
|
+
else if (cs == EDN_vector_error) {
|
716
|
+
error(__FUNCTION__, "vector format error", *p);
|
717
|
+
return pe;
|
718
|
+
}
|
719
|
+
else if (cs == EDN_vector_en_main) {} // silence ragel warning
|
720
|
+
return nullptr;
|
661
721
|
}
|
662
722
|
|
663
723
|
|
@@ -666,16 +726,16 @@ const char* edn::Parser::parse_vector(const char *p, const char *pe, VALUE& v)
|
|
666
726
|
// list parsing machine
|
667
727
|
//
|
668
728
|
%%{
|
669
|
-
|
670
|
-
|
729
|
+
machine EDN_list;
|
730
|
+
include EDN_sequence_common;
|
671
731
|
|
672
|
-
|
732
|
+
end_list = ')';
|
673
733
|
|
674
|
-
|
734
|
+
write data;
|
675
735
|
|
676
|
-
|
677
|
-
|
678
|
-
|
736
|
+
main := begin_list @open_seq (
|
737
|
+
ignore* sequence? :>> end_list @close_seq
|
738
|
+
) @err(close_err) @exit;
|
679
739
|
}%%
|
680
740
|
|
681
741
|
//
|
@@ -683,26 +743,24 @@ const char* edn::Parser::parse_vector(const char *p, const char *pe, VALUE& v)
|
|
683
743
|
//
|
684
744
|
const char* edn::Parser::parse_list(const char *p, const char *pe, VALUE& v)
|
685
745
|
{
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
else if (cs == EDN_list_en_main) {} // silence ragel warning
|
705
|
-
return NULL;
|
746
|
+
static const char* EDN_TYPE = "list";
|
747
|
+
|
748
|
+
int cs;
|
749
|
+
VALUE elems; // stores the list's elements - allocated in @open_seq
|
750
|
+
|
751
|
+
%% write init;
|
752
|
+
%% write exec;
|
753
|
+
|
754
|
+
if (cs >= EDN_list_first_final) {
|
755
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_LIST_METHOD, elems);
|
756
|
+
return p + 1;
|
757
|
+
}
|
758
|
+
else if (cs == EDN_list_error) {
|
759
|
+
error(__FUNCTION__, *p);
|
760
|
+
return pe;
|
761
|
+
}
|
762
|
+
else if (cs == EDN_list_en_main) {} // silence ragel warning
|
763
|
+
return nullptr;
|
706
764
|
}
|
707
765
|
|
708
766
|
|
@@ -711,56 +769,55 @@ const char* edn::Parser::parse_list(const char *p, const char *pe, VALUE& v)
|
|
711
769
|
// hash parsing
|
712
770
|
//
|
713
771
|
%%{
|
714
|
-
|
715
|
-
|
772
|
+
machine EDN_map;
|
773
|
+
include EDN_sequence_common;
|
716
774
|
|
717
|
-
|
775
|
+
end_map = '}';
|
718
776
|
|
719
|
-
|
777
|
+
write data;
|
720
778
|
|
721
779
|
|
722
|
-
|
723
|
-
|
724
|
-
|
780
|
+
main := begin_map @open_seq (
|
781
|
+
ignore* (sequence)? :>> end_map @close_seq
|
782
|
+
) @err(close_err) @exit;
|
725
783
|
}%%
|
726
784
|
|
727
785
|
|
728
786
|
const char* edn::Parser::parse_map(const char *p, const char *pe, VALUE& v)
|
729
787
|
{
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
return NULL;
|
788
|
+
static const char* EDN_TYPE = "map";
|
789
|
+
|
790
|
+
int cs;
|
791
|
+
// since we don't know whether we're looking at a key or value,
|
792
|
+
// initially store all elements in an array (allocated in @open_seq)
|
793
|
+
VALUE elems;
|
794
|
+
|
795
|
+
%% write init;
|
796
|
+
%% write exec;
|
797
|
+
|
798
|
+
if (cs >= EDN_map_first_final) {
|
799
|
+
// hash parsing is done. Make sure we have an even count
|
800
|
+
if ((RARRAY_LEN(elems) % 2) != 0) {
|
801
|
+
error(__FUNCTION__, "odd number of elements in map");
|
802
|
+
return pe;
|
803
|
+
}
|
804
|
+
|
805
|
+
// now convert the sequence to a hash
|
806
|
+
VALUE rslt = rb_hash_new();
|
807
|
+
while (RARRAY_LEN(elems) > 0)
|
808
|
+
{
|
809
|
+
VALUE k = rb_ary_shift(elems);
|
810
|
+
rb_hash_aset(rslt, k, rb_ary_shift(elems));
|
811
|
+
}
|
812
|
+
|
813
|
+
v = rslt;
|
814
|
+
return p + 1;
|
815
|
+
}
|
816
|
+
else if (cs == EDN_map_error) {
|
817
|
+
return pe;
|
818
|
+
}
|
819
|
+
else if (cs == EDN_map_en_main) {} // silence ragel warning
|
820
|
+
return nullptr;
|
764
821
|
}
|
765
822
|
|
766
823
|
|
@@ -771,55 +828,73 @@ const char* edn::Parser::parse_map(const char *p, const char *pe, VALUE& v)
|
|
771
828
|
// the remaining data to the correct parser
|
772
829
|
//
|
773
830
|
%%{
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
831
|
+
machine EDN_dispatch;
|
832
|
+
include EDN_common;
|
833
|
+
|
834
|
+
write data;
|
835
|
+
|
836
|
+
action parse_disp_set {
|
837
|
+
// #{ }
|
838
|
+
const char *np = parse_set(fpc, pe, v);
|
839
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
840
|
+
}
|
841
|
+
|
842
|
+
action parse_disp_discard {
|
843
|
+
// discard token #_
|
844
|
+
const char *np = parse_discard(fpc, pe);
|
845
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
846
|
+
}
|
847
|
+
|
848
|
+
action parse_disp_tagged {
|
849
|
+
// #inst, #uuid, or #user/tag
|
850
|
+
const char *np = parse_tagged(fpc, pe, v);
|
851
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
852
|
+
}
|
853
|
+
|
854
|
+
action parse_disp_symbol {
|
855
|
+
// ##Inf, ##NaN, etc.
|
856
|
+
VALUE sym = Qnil;
|
857
|
+
const char *np = parse_symbol(fpc+1, pe, sym);
|
858
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
859
|
+
if (std::strcmp(RSTRING_PTR(sym), "NaN") == 0) {
|
860
|
+
v = RUBY_NAN_CONST;
|
861
|
+
}
|
862
|
+
else if (std::strcmp(RSTRING_PTR(sym), "Inf") == 0) {
|
863
|
+
v = RUBY_INF_CONST;
|
864
|
+
}
|
865
|
+
else {
|
866
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SYMBOL_METHOD, sym);
|
867
|
+
}
|
868
|
+
|
869
|
+
fexec np;
|
870
|
+
}
|
871
|
+
}
|
872
|
+
|
873
|
+
main := (
|
874
|
+
('{' >parse_disp_set |
|
875
|
+
'_' >parse_disp_discard |
|
876
|
+
'#' >parse_disp_symbol |
|
877
|
+
alpha >parse_disp_tagged)
|
878
|
+
) @exit;
|
803
879
|
}%%
|
804
880
|
|
805
881
|
|
806
882
|
const char* edn::Parser::parse_dispatch(const char *p, const char *pe, VALUE& v)
|
807
883
|
{
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
return NULL;
|
884
|
+
int cs;
|
885
|
+
|
886
|
+
%% write init;
|
887
|
+
%% write exec;
|
888
|
+
|
889
|
+
if (cs >= EDN_dispatch_first_final) {
|
890
|
+
return p + 1;
|
891
|
+
}
|
892
|
+
else if (cs == EDN_dispatch_error) {
|
893
|
+
error(__FUNCTION__, "dispatch extend error", *p);
|
894
|
+
return pe;
|
895
|
+
}
|
896
|
+
else if (cs == EDN_dispatch_en_main) {} // silence ragel warning
|
897
|
+
return nullptr;
|
823
898
|
}
|
824
899
|
|
825
900
|
|
@@ -827,17 +902,17 @@ const char* edn::Parser::parse_dispatch(const char *p, const char *pe, VALUE& v)
|
|
827
902
|
// set parsing machine
|
828
903
|
//
|
829
904
|
%%{
|
830
|
-
|
831
|
-
|
905
|
+
machine EDN_set;
|
906
|
+
include EDN_sequence_common;
|
832
907
|
|
833
|
-
|
908
|
+
write data;
|
834
909
|
|
835
|
-
|
836
|
-
|
910
|
+
begin_set = '{';
|
911
|
+
end_set = '}';
|
837
912
|
|
838
|
-
|
839
|
-
|
840
|
-
|
913
|
+
main := begin_set @open_seq (
|
914
|
+
ignore* sequence? :>> end_set @close_seq
|
915
|
+
) @err(close_err) @exit;
|
841
916
|
}%%
|
842
917
|
|
843
918
|
//
|
@@ -845,25 +920,25 @@ const char* edn::Parser::parse_dispatch(const char *p, const char *pe, VALUE& v)
|
|
845
920
|
//
|
846
921
|
const char* edn::Parser::parse_set(const char *p, const char *pe, VALUE& v)
|
847
922
|
{
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
923
|
+
static const char* EDN_TYPE = "set";
|
924
|
+
|
925
|
+
int cs;
|
926
|
+
VALUE elems; // holds the set's elements as an array allocated in @open_seq
|
927
|
+
|
928
|
+
%% write init;
|
929
|
+
%% write exec;
|
930
|
+
|
931
|
+
if (cs >= EDN_set_first_final) {
|
932
|
+
// all elements collected; now convert to a set
|
933
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SET_METHOD, elems);
|
934
|
+
return p + 1;
|
935
|
+
}
|
936
|
+
else if (cs == EDN_set_error) {
|
937
|
+
error(__FUNCTION__, *p);
|
938
|
+
return pe;
|
939
|
+
}
|
940
|
+
else if (cs == EDN_set_en_main) {} // silence ragel warning
|
941
|
+
return nullptr;
|
867
942
|
}
|
868
943
|
|
869
944
|
|
@@ -874,55 +949,54 @@ const char* edn::Parser::parse_set(const char *p, const char *pe, VALUE& v)
|
|
874
949
|
// defining a machine to consume items within container delimiters
|
875
950
|
//
|
876
951
|
%%{
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
952
|
+
machine EDN_discard;
|
953
|
+
include EDN_common;
|
954
|
+
|
955
|
+
write data;
|
956
|
+
|
957
|
+
begin_discard = '_';
|
958
|
+
|
959
|
+
action discard_value {
|
960
|
+
const char *np = parse_value(fpc, pe, v);
|
961
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
962
|
+
// this token is to be discarded so store it in the
|
963
|
+
// discard stack - we really don't need to save it so this
|
964
|
+
// could be simplified
|
965
|
+
discard.push_back(v);
|
966
|
+
fexec np;
|
967
|
+
}
|
968
|
+
}
|
969
|
+
|
970
|
+
action discard_err {
|
971
|
+
std::stringstream s;
|
972
|
+
s << "discard sequence without element to discard";
|
973
|
+
error(__FUNCTION__, s.str());
|
974
|
+
fhold; fbreak;
|
975
|
+
}
|
976
|
+
|
977
|
+
main := begin_discard ignore* (
|
978
|
+
begin_value >discard_value
|
979
|
+
) @err(discard_err) @exit;
|
905
980
|
}%%
|
906
981
|
|
907
982
|
|
908
983
|
const char* edn::Parser::parse_discard(const char *p, const char *pe)
|
909
984
|
{
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
return NULL;
|
985
|
+
int cs;
|
986
|
+
VALUE v;
|
987
|
+
|
988
|
+
%% write init;
|
989
|
+
%% write exec;
|
990
|
+
|
991
|
+
if (cs >= EDN_discard_first_final) {
|
992
|
+
return p + 1;
|
993
|
+
}
|
994
|
+
else if (cs == EDN_discard_error) {
|
995
|
+
error(__FUNCTION__, *p);
|
996
|
+
return pe;
|
997
|
+
}
|
998
|
+
else if (cs == EDN_discard_en_main) {} // silence ragel warning
|
999
|
+
return nullptr;
|
926
1000
|
}
|
927
1001
|
|
928
1002
|
|
@@ -942,130 +1016,127 @@ const char* edn::Parser::parse_discard(const char *p, const char *pe)
|
|
942
1016
|
// 2. add parse checks for uuid and inst for better error reporting
|
943
1017
|
//
|
944
1018
|
%%{
|
945
|
-
|
946
|
-
|
1019
|
+
machine EDN_tagged;
|
1020
|
+
include EDN_common;
|
947
1021
|
|
948
|
-
|
1022
|
+
write data;
|
949
1023
|
|
950
|
-
|
951
|
-
|
952
|
-
|
1024
|
+
tag_symbol_chars_start = alpha;
|
1025
|
+
tag_symbol_chars_non_numeric = tag_symbol_chars_start | [\.\*!_\?$%&<>\=+\-\'\:\#];
|
1026
|
+
tag_symbol_chars = tag_symbol_chars_non_numeric | digit;
|
953
1027
|
|
954
|
-
|
955
|
-
|
1028
|
+
tag_symbol_namespace = tag_symbol_chars_start (tag_symbol_chars)*;
|
1029
|
+
tag_symbol_name = tag_symbol_chars_non_numeric (tag_symbol_chars)*;
|
956
1030
|
|
957
|
-
|
1031
|
+
tag_symbol = (tag_symbol_namespace ('/' tag_symbol_name)?);
|
958
1032
|
|
959
1033
|
# inst = (string_delim [0-9+\-:\.TZ]* string_delim);
|
960
1034
|
# uuid = (string_delim [a-f0-9\-]* string_delim);
|
961
1035
|
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
1036
|
+
action parse_tag {
|
1037
|
+
// parses the symbol portion of the pair
|
1038
|
+
const char *np = parse_symbol(fpc, pe, sym_name);
|
1039
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
1040
|
+
sym_ok = true;
|
1041
|
+
fexec np;
|
1042
|
+
}
|
1043
|
+
}
|
1044
|
+
action parse_data {
|
1045
|
+
// parses the value portion
|
1046
|
+
const char *np = parse_value(fpc, pe, data);
|
1047
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
1048
|
+
data_ok = true;
|
1049
|
+
fexec np;
|
1050
|
+
}
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
main := (
|
1054
|
+
tag_symbol >parse_tag ignore+
|
1055
|
+
begin_value >parse_data
|
1056
|
+
) @exit;
|
983
1057
|
}%%
|
984
1058
|
|
985
1059
|
|
986
1060
|
const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
987
1061
|
{
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
1062
|
+
VALUE sym_name = Qnil;
|
1063
|
+
VALUE data = Qnil;
|
1064
|
+
bool sym_ok = false;
|
1065
|
+
bool data_ok = false;
|
992
1066
|
|
993
|
-
|
1067
|
+
int cs;
|
994
1068
|
|
995
|
-
|
996
|
-
|
1069
|
+
%% write init;
|
1070
|
+
%% write exec;
|
997
1071
|
|
998
|
-
|
1072
|
+
if (cs >= EDN_tagged_first_final) {
|
999
1073
|
//std::cerr << __FUNCTION__ << " parse symbol name as '" << sym_name << "', value is: " << data << std::endl;
|
1000
1074
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1075
|
+
if (!sym_ok || !data_ok) {
|
1076
|
+
error(__FUNCTION__, "tagged element symbol error", *p);
|
1077
|
+
v = EDN_EOF_CONST;
|
1078
|
+
return nullptr;
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
try {
|
1082
|
+
// tagged_element makes a call to ruby which may throw an
|
1083
|
+
// exception when parsing the data
|
1084
|
+
v = edn::util::call_module_fn(rb_mEDN, EDN_TAGGED_ELEM_METHOD, sym_name, data);
|
1085
|
+
return p + 1;
|
1086
|
+
} catch (std::exception& e) {
|
1087
|
+
error(__FUNCTION__, e.what());
|
1088
|
+
return pe;
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
else if (cs == EDN_tagged_error) {
|
1092
|
+
error(__FUNCTION__, "tagged element symbol error", *p);
|
1093
|
+
}
|
1094
|
+
else if (cs == EDN_tagged_en_main) {} // silence ragel warning
|
1095
|
+
v = EDN_EOF_CONST;
|
1096
|
+
return nullptr;
|
1023
1097
|
}
|
1024
1098
|
|
1025
1099
|
|
1026
|
-
|
1027
|
-
|
1028
1100
|
// ============================================================
|
1029
1101
|
// metadata - looks like ruby just discards this but we'll track it
|
1030
1102
|
// and provide a means to retrive after each parse op - might be
|
1031
1103
|
// useful?
|
1032
1104
|
//
|
1033
1105
|
%%{
|
1034
|
-
|
1035
|
-
|
1106
|
+
machine EDN_meta;
|
1107
|
+
include EDN_common;
|
1036
1108
|
|
1037
|
-
|
1109
|
+
write data;
|
1038
1110
|
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1111
|
+
action parse_data {
|
1112
|
+
const char *np = parse_value(fpc, pe, v);
|
1113
|
+
if (np == nullptr) { fhold; fbreak; } else { fexec np; }
|
1114
|
+
}
|
1043
1115
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1116
|
+
main := begin_meta (
|
1117
|
+
begin_value >parse_data
|
1118
|
+
) @exit;
|
1047
1119
|
}%%
|
1048
1120
|
|
1049
1121
|
|
1050
1122
|
const char* edn::Parser::parse_meta(const char *p, const char *pe)
|
1051
1123
|
{
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
return NULL;
|
1124
|
+
int cs;
|
1125
|
+
VALUE v;
|
1126
|
+
|
1127
|
+
%% write init;
|
1128
|
+
%% write exec;
|
1129
|
+
|
1130
|
+
if (cs >= EDN_meta_first_final) {
|
1131
|
+
append_to_meta(v);
|
1132
|
+
return p + 1;
|
1133
|
+
}
|
1134
|
+
else if (cs == EDN_meta_error) {
|
1135
|
+
error(__FUNCTION__, *p);
|
1136
|
+
return pe;
|
1137
|
+
}
|
1138
|
+
else if (cs == EDN_meta_en_main) {} // silence ragel warning
|
1139
|
+
return nullptr;
|
1069
1140
|
}
|
1070
1141
|
|
1071
1142
|
|
@@ -1075,55 +1146,55 @@ const char* edn::Parser::parse_meta(const char *p, const char *pe)
|
|
1075
1146
|
// top-level, therefore, does not tokenize source stream
|
1076
1147
|
//
|
1077
1148
|
%%{
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1149
|
+
machine EDN_parser;
|
1150
|
+
include EDN_common;
|
1151
|
+
|
1152
|
+
write data;
|
1153
|
+
|
1154
|
+
action parse_elem {
|
1155
|
+
// save the count of metadata items before we parse this value
|
1156
|
+
// so we can determine if we've read another metadata value or
|
1157
|
+
// an actual data item
|
1158
|
+
std::size_t meta_sz = meta_size();
|
1159
|
+
const char* np = parse_value(fpc, pe, result);
|
1160
|
+
if (np == nullptr) { fexec pe; fbreak; } else {
|
1161
|
+
// if we have metadata saved and it matches the count we
|
1162
|
+
// saved before we parsed a value, then we must bind the
|
1163
|
+
// metadata sequence to it
|
1164
|
+
if (!meta_empty() && meta_size() == meta_sz) {
|
1165
|
+
// this will empty the metadata sequence too
|
1166
|
+
result = edn::util::call_module_fn(rb_mEDNT, EDNT_EXTENDED_VALUE_METHOD, result, ruby_meta());
|
1167
|
+
}
|
1168
|
+
fexec np;
|
1169
|
+
}
|
1170
|
+
}
|
1171
|
+
|
1172
|
+
element = begin_value >parse_elem;
|
1173
|
+
next_element = ignore* element;
|
1174
|
+
sequence = ((element ignore*) (next_element ignore*)*);
|
1175
|
+
|
1176
|
+
main := ignore* sequence? ignore*;
|
1106
1177
|
}%%
|
1107
1178
|
|
1108
1179
|
|
1109
1180
|
VALUE edn::Parser::parse(const char* src, std::size_t len)
|
1110
1181
|
{
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1182
|
+
int cs;
|
1183
|
+
VALUE result = EDN_EOF_CONST;
|
1184
|
+
|
1185
|
+
%% write init;
|
1186
|
+
set_source(src, len);
|
1187
|
+
%% write exec;
|
1188
|
+
|
1189
|
+
if (cs == EDN_parser_error) {
|
1190
|
+
error(__FUNCTION__, *p);
|
1191
|
+
return EDN_EOF_CONST;
|
1192
|
+
}
|
1193
|
+
else if (cs == EDN_parser_first_final) {
|
1194
|
+
p = pe = eof = nullptr;
|
1195
|
+
}
|
1196
|
+
else if (cs == EDN_parser_en_main) {} // silence ragel warning
|
1197
|
+
return result;
|
1127
1198
|
}
|
1128
1199
|
|
1129
1200
|
|
@@ -1131,43 +1202,43 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
1131
1202
|
// token-by-token machine
|
1132
1203
|
//
|
1133
1204
|
%%{
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
}
|
1154
|
-
else {
|
1155
|
-
// a value was read and there's a pending metadata
|
1156
|
-
// sequence. Bind them.
|
1157
|
-
value = edn::util::call_module_fn(rb_mEDNT, EDNT_EXTENDED_VALUE_METHOD, value, ruby_meta());
|
1158
|
-
state = TOKEN_OK;
|
1159
|
-
}
|
1160
|
-
} else if (!discard.empty()) {
|
1161
|
-
// a discard read. Don't return a value
|
1162
|
-
state = TOKEN_IS_DISCARD;
|
1163
|
-
} else {
|
1164
|
-
state = TOKEN_OK;
|
1205
|
+
machine EDN_tokens;
|
1206
|
+
include EDN_common;
|
1207
|
+
|
1208
|
+
write data nofinal noerror;
|
1209
|
+
|
1210
|
+
action parse_token {
|
1211
|
+
// we won't know if we've parsed a discard or a metadata until
|
1212
|
+
// after parse_value() is done. Save the current number of
|
1213
|
+
// elements in the metadata sequence; then we can check if it
|
1214
|
+
// grew or if the discard sequence grew
|
1215
|
+
meta_sz = meta_size();
|
1216
|
+
|
1217
|
+
const char* np = parse_value(fpc, pe, value);
|
1218
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
1219
|
+
if (!meta_empty()) {
|
1220
|
+
// was an additional metadata entry read? if so, don't
|
1221
|
+
// return a value
|
1222
|
+
if (meta_size() > meta_sz) {
|
1223
|
+
state = TOKEN_IS_META;
|
1165
1224
|
}
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1225
|
+
else {
|
1226
|
+
// a value was read and there's a pending metadata
|
1227
|
+
// sequence. Bind them.
|
1228
|
+
value = edn::util::call_module_fn(rb_mEDNT, EDNT_EXTENDED_VALUE_METHOD, value, ruby_meta());
|
1229
|
+
state = TOKEN_OK;
|
1230
|
+
}
|
1231
|
+
} else if (!discard.empty()) {
|
1232
|
+
// a discard read. Don't return a value
|
1233
|
+
state = TOKEN_IS_DISCARD;
|
1234
|
+
} else {
|
1235
|
+
state = TOKEN_OK;
|
1236
|
+
}
|
1237
|
+
fexec np;
|
1238
|
+
}
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
main := ignore* begin_value >parse_token ignore*;
|
1171
1242
|
}%%
|
1172
1243
|
|
1173
1244
|
|
@@ -1175,21 +1246,21 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
1175
1246
|
//
|
1176
1247
|
edn::Parser::eTokenState edn::Parser::parse_next(VALUE& value)
|
1177
1248
|
{
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1249
|
+
int cs;
|
1250
|
+
eTokenState state = TOKEN_ERROR;
|
1251
|
+
// need to track metadada read and bind it to the next value read
|
1252
|
+
// - but must account for sequences of metadata values
|
1253
|
+
std::size_t meta_sz;
|
1183
1254
|
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1255
|
+
// clear any previously saved discards; only track if read during
|
1256
|
+
// this op
|
1257
|
+
discard.clear();
|
1187
1258
|
|
1188
|
-
|
1189
|
-
|
1259
|
+
%% write init;
|
1260
|
+
%% write exec;
|
1190
1261
|
|
1191
|
-
|
1192
|
-
|
1262
|
+
if (cs == EDN_tokens_en_main) {} // silence ragel warning
|
1263
|
+
return state;
|
1193
1264
|
}
|
1194
1265
|
|
1195
1266
|
/*
|