edn_turbo 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rspec +1 -0
- data/CHANGELOG.md +15 -0
- data/Dockerfile +34 -0
- data/LICENSE +1 -1
- data/README.md +8 -22
- data/Rakefile +22 -19
- data/bin/build_docker_image.sh +11 -0
- data/bin/console.sh +5 -0
- data/docker-compose.yml +10 -0
- data/ext/edn_turbo/edn_parser.cc +336 -314
- data/ext/edn_turbo/edn_parser.rl +63 -41
- data/ext/edn_turbo/extconf.rb +24 -1
- data/ext/edn_turbo/main.cc +189 -166
- data/ext/edn_turbo/parser.h +104 -76
- data/ext/edn_turbo/parser_def.cc +204 -182
- data/ext/edn_turbo/util.cc +241 -219
- data/ext/edn_turbo/util.h +48 -26
- data/ext/edn_turbo/util_unicode.cc +41 -19
- data/ext/edn_turbo/util_unicode.h +29 -7
- data/lib/edn_turbo.rb +22 -0
- data/lib/edn_turbo/edn_parser.rb +22 -0
- data/lib/edn_turbo/version.rb +23 -3
- data/spec/edn_turbo/edn_parser_spec.rb +384 -0
- data/spec/spec_helper.rb +96 -0
- metadata +42 -11
- 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-2019 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>
|
@@ -71,20 +93,20 @@
|
|
71
93
|
action parse_val_string {
|
72
94
|
// string types within double-quotes
|
73
95
|
const char *np = parse_string(fpc, pe, v);
|
74
|
-
if (np ==
|
96
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
75
97
|
}
|
76
98
|
|
77
99
|
action parse_val_keyword {
|
78
100
|
// tokens with a leading ':'
|
79
101
|
const char *np = parse_keyword(fpc, pe, v);
|
80
|
-
if (np ==
|
102
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
81
103
|
}
|
82
104
|
|
83
105
|
action parse_val_number {
|
84
106
|
// tokens w/ leading digits: non-negative integers & decimals.
|
85
107
|
// try to parse a decimal first
|
86
108
|
const char *np = parse_decimal(fpc, pe, v);
|
87
|
-
if (np ==
|
109
|
+
if (np == nullptr) {
|
88
110
|
// if we can't, try to parse it as an int
|
89
111
|
np = parse_integer(fpc, pe, v);
|
90
112
|
}
|
@@ -103,20 +125,20 @@
|
|
103
125
|
action parse_val_operator {
|
104
126
|
// stand-alone operators *, +, -, etc.
|
105
127
|
const char *np = parse_operator(fpc, pe, v);
|
106
|
-
if (np ==
|
128
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
107
129
|
}
|
108
130
|
|
109
131
|
action parse_val_char {
|
110
132
|
// tokens w/ leading \ (escaped characters \newline, \c, etc.)
|
111
133
|
const char *np = parse_esc_char(fpc, pe, v);
|
112
|
-
if (np ==
|
134
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
113
135
|
}
|
114
136
|
|
115
137
|
action parse_val_symbol {
|
116
138
|
// user identifiers and reserved keywords (true, false, nil)
|
117
139
|
VALUE sym = Qnil;
|
118
140
|
const char *np = parse_symbol(fpc, pe, sym);
|
119
|
-
if (np ==
|
141
|
+
if (np == nullptr) { fexec pe; } else {
|
120
142
|
// parse_symbol will make 'sym' a ruby string
|
121
143
|
if (std::strcmp(RSTRING_PTR(sym), "true") == 0) { v = Qtrue; }
|
122
144
|
else if (std::strcmp(RSTRING_PTR(sym), "false") == 0) { v = Qfalse; }
|
@@ -131,31 +153,31 @@
|
|
131
153
|
action parse_val_vector {
|
132
154
|
// [
|
133
155
|
const char *np = parse_vector(fpc, pe, v);
|
134
|
-
if (np ==
|
156
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
135
157
|
}
|
136
158
|
|
137
159
|
action parse_val_list {
|
138
160
|
// (
|
139
161
|
const char *np = parse_list(fpc, pe, v);
|
140
|
-
if (np ==
|
162
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
141
163
|
}
|
142
164
|
|
143
165
|
action parse_val_map {
|
144
166
|
// {
|
145
167
|
const char *np = parse_map(fpc, pe, v);
|
146
|
-
if (np ==
|
168
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
147
169
|
}
|
148
170
|
|
149
171
|
action parse_val_meta {
|
150
172
|
// ^
|
151
173
|
const char *np = parse_meta(fpc, pe);
|
152
|
-
if (np ==
|
174
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
153
175
|
}
|
154
176
|
|
155
177
|
action parse_val_dispatch {
|
156
178
|
// handles tokens w/ leading # ("#_", "#{", and tagged elems)
|
157
179
|
const char *np = parse_dispatch(fpc + 1, pe, v);
|
158
|
-
if (np ==
|
180
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
159
181
|
}
|
160
182
|
|
161
183
|
|
@@ -191,7 +213,7 @@ const char *edn::Parser::parse_value(const char *p, const char *pe, VALUE& v)
|
|
191
213
|
return pe;
|
192
214
|
}
|
193
215
|
else if (cs == EDN_value_en_main) {} // silence ragel warning
|
194
|
-
return
|
216
|
+
return nullptr;
|
195
217
|
}
|
196
218
|
|
197
219
|
|
@@ -247,7 +269,7 @@ const char* edn::Parser::parse_string(const char *p, const char *pe, VALUE& v)
|
|
247
269
|
return pe;
|
248
270
|
}
|
249
271
|
else if (cs == EDN_string_en_main) {} // silence ragel warning
|
250
|
-
return
|
272
|
+
return nullptr;
|
251
273
|
}
|
252
274
|
|
253
275
|
|
@@ -293,7 +315,7 @@ const char* edn::Parser::parse_keyword(const char *p, const char *pe, VALUE& v)
|
|
293
315
|
return pe;
|
294
316
|
}
|
295
317
|
else if (cs == EDN_keyword_en_main) {} // silence ragel warning
|
296
|
-
return
|
318
|
+
return nullptr;
|
297
319
|
}
|
298
320
|
|
299
321
|
|
@@ -328,7 +350,7 @@ const char* edn::Parser::parse_decimal(const char *p, const char *pe, VALUE& v)
|
|
328
350
|
return p + 1;
|
329
351
|
}
|
330
352
|
else if (cs == EDN_decimal_en_main) {} // silence ragel warning
|
331
|
-
return
|
353
|
+
return nullptr;
|
332
354
|
}
|
333
355
|
|
334
356
|
|
@@ -360,7 +382,7 @@ const char* edn::Parser::parse_integer(const char *p, const char *pe, VALUE& v)
|
|
360
382
|
return p + 1;
|
361
383
|
}
|
362
384
|
else if (cs == EDN_integer_en_main) {} // silence ragel warning
|
363
|
-
return
|
385
|
+
return nullptr;
|
364
386
|
}
|
365
387
|
|
366
388
|
|
@@ -382,7 +404,7 @@ const char* edn::Parser::parse_integer(const char *p, const char *pe, VALUE& v)
|
|
382
404
|
// parse a symbol including the leading operator (-, +, .)
|
383
405
|
VALUE sym = Qnil;
|
384
406
|
const char *np = parse_symbol(p_save, pe, sym);
|
385
|
-
if (np ==
|
407
|
+
if (np == nullptr) { fexec pe; } else {
|
386
408
|
if (sym != Qnil)
|
387
409
|
v = edn::util::call_module_fn(rb_mEDN, EDN_MAKE_SYMBOL_METHOD, sym);
|
388
410
|
fexec np;
|
@@ -396,7 +418,7 @@ const char* edn::Parser::parse_integer(const char *p, const char *pe, VALUE& v)
|
|
396
418
|
//
|
397
419
|
// try to parse a decimal first
|
398
420
|
const char *np = parse_decimal(p_save, pe, v);
|
399
|
-
if (np ==
|
421
|
+
if (np == nullptr) {
|
400
422
|
// if we can't, try to parse it as an int
|
401
423
|
np = parse_integer(p_save, pe, v);
|
402
424
|
}
|
@@ -447,7 +469,7 @@ const char* edn::Parser::parse_operator(const char *p, const char *pe, VALUE& v)
|
|
447
469
|
return pe;
|
448
470
|
}
|
449
471
|
else if (cs == EDN_operator_en_main) {} // silence ragel warning
|
450
|
-
return
|
472
|
+
return nullptr;
|
451
473
|
}
|
452
474
|
|
453
475
|
|
@@ -491,7 +513,7 @@ const char* edn::Parser::parse_esc_char(const char *p, const char *pe, VALUE& v)
|
|
491
513
|
return pe;
|
492
514
|
}
|
493
515
|
else if (cs == EDN_escaped_char_en_main) {} // silence ragel warning
|
494
|
-
return
|
516
|
+
return nullptr;
|
495
517
|
}
|
496
518
|
|
497
519
|
|
@@ -551,7 +573,7 @@ const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
|
551
573
|
error(__FUNCTION__, "invalid symbol sequence", *p);
|
552
574
|
}
|
553
575
|
else if (cs == EDN_symbol_en_main) {} // silence ragel warning
|
554
|
-
return
|
576
|
+
return nullptr;
|
555
577
|
}
|
556
578
|
|
557
579
|
|
@@ -589,7 +611,7 @@ const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
|
589
611
|
VALUE e;
|
590
612
|
std::size_t meta_sz = meta_size();
|
591
613
|
const char *np = parse_value(fpc, pe, e);
|
592
|
-
if (np ==
|
614
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
593
615
|
// if there's an entry in the discard list, the current
|
594
616
|
// object is not meant to be kept due to a #_ so don't
|
595
617
|
// push it into the list of elements
|
@@ -657,7 +679,7 @@ const char* edn::Parser::parse_vector(const char *p, const char *pe, VALUE& v)
|
|
657
679
|
return pe;
|
658
680
|
}
|
659
681
|
else if (cs == EDN_vector_en_main) {} // silence ragel warning
|
660
|
-
return
|
682
|
+
return nullptr;
|
661
683
|
}
|
662
684
|
|
663
685
|
|
@@ -702,7 +724,7 @@ const char* edn::Parser::parse_list(const char *p, const char *pe, VALUE& v)
|
|
702
724
|
return pe;
|
703
725
|
}
|
704
726
|
else if (cs == EDN_list_en_main) {} // silence ragel warning
|
705
|
-
return
|
727
|
+
return nullptr;
|
706
728
|
}
|
707
729
|
|
708
730
|
|
@@ -760,7 +782,7 @@ const char* edn::Parser::parse_map(const char *p, const char *pe, VALUE& v)
|
|
760
782
|
return pe;
|
761
783
|
}
|
762
784
|
else if (cs == EDN_map_en_main) {} // silence ragel warning
|
763
|
-
return
|
785
|
+
return nullptr;
|
764
786
|
}
|
765
787
|
|
766
788
|
|
@@ -779,19 +801,19 @@ const char* edn::Parser::parse_map(const char *p, const char *pe, VALUE& v)
|
|
779
801
|
action parse_disp_set {
|
780
802
|
// #{ }
|
781
803
|
const char *np = parse_set(fpc, pe, v);
|
782
|
-
if (np ==
|
804
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
783
805
|
}
|
784
806
|
|
785
807
|
action parse_disp_discard {
|
786
808
|
// discard token #_
|
787
809
|
const char *np = parse_discard(fpc, pe);
|
788
|
-
if (np ==
|
810
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
789
811
|
}
|
790
812
|
|
791
813
|
action parse_disp_tagged {
|
792
814
|
// #inst, #uuid, or #user/tag
|
793
815
|
const char *np = parse_tagged(fpc, pe, v);
|
794
|
-
if (np ==
|
816
|
+
if (np == nullptr) { fhold; fbreak; } else fexec np;
|
795
817
|
}
|
796
818
|
|
797
819
|
|
@@ -819,7 +841,7 @@ const char* edn::Parser::parse_dispatch(const char *p, const char *pe, VALUE& v)
|
|
819
841
|
}
|
820
842
|
else if (cs == EDN_dispatch_en_main) {} // silence ragel warning
|
821
843
|
|
822
|
-
return
|
844
|
+
return nullptr;
|
823
845
|
}
|
824
846
|
|
825
847
|
|
@@ -863,7 +885,7 @@ const char* edn::Parser::parse_set(const char *p, const char *pe, VALUE& v)
|
|
863
885
|
return pe;
|
864
886
|
}
|
865
887
|
else if (cs == EDN_set_en_main) {} // silence ragel warning
|
866
|
-
return
|
888
|
+
return nullptr;
|
867
889
|
}
|
868
890
|
|
869
891
|
|
@@ -883,7 +905,7 @@ const char* edn::Parser::parse_set(const char *p, const char *pe, VALUE& v)
|
|
883
905
|
|
884
906
|
action discard_value {
|
885
907
|
const char *np = parse_value(fpc, pe, v);
|
886
|
-
if (np ==
|
908
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
887
909
|
// this token is to be discarded so store it in the
|
888
910
|
// discard stack - we really don't need to save it so this
|
889
911
|
// could be simplified
|
@@ -922,7 +944,7 @@ const char* edn::Parser::parse_discard(const char *p, const char *pe)
|
|
922
944
|
}
|
923
945
|
else if (cs == EDN_discard_en_main) {} // silence ragel warning
|
924
946
|
|
925
|
-
return
|
947
|
+
return nullptr;
|
926
948
|
}
|
927
949
|
|
928
950
|
|
@@ -962,7 +984,7 @@ const char* edn::Parser::parse_discard(const char *p, const char *pe)
|
|
962
984
|
action parse_tag {
|
963
985
|
// parses the symbol portion of the pair
|
964
986
|
const char *np = parse_symbol(fpc, pe, sym_name);
|
965
|
-
if (np ==
|
987
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
966
988
|
sym_ok = true;
|
967
989
|
fexec np;
|
968
990
|
}
|
@@ -970,7 +992,7 @@ const char* edn::Parser::parse_discard(const char *p, const char *pe)
|
|
970
992
|
action parse_data {
|
971
993
|
// parses the value portion
|
972
994
|
const char *np = parse_value(fpc, pe, data);
|
973
|
-
if (np ==
|
995
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
974
996
|
data_ok = true;
|
975
997
|
fexec np;
|
976
998
|
}
|
@@ -1001,7 +1023,7 @@ const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
|
1001
1023
|
if (!sym_ok || !data_ok) {
|
1002
1024
|
error(__FUNCTION__, "tagged element symbol error", *p);
|
1003
1025
|
v = EDN_EOF_CONST;
|
1004
|
-
return
|
1026
|
+
return nullptr;
|
1005
1027
|
}
|
1006
1028
|
|
1007
1029
|
try {
|
@@ -1019,7 +1041,7 @@ const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
|
1019
1041
|
}
|
1020
1042
|
else if (cs == EDN_tagged_en_main) {} // silence ragel warning
|
1021
1043
|
v = EDN_EOF_CONST;
|
1022
|
-
return
|
1044
|
+
return nullptr;
|
1023
1045
|
}
|
1024
1046
|
|
1025
1047
|
|
@@ -1038,7 +1060,7 @@ const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
|
1038
1060
|
|
1039
1061
|
action parse_data {
|
1040
1062
|
const char *np = parse_value(fpc, pe, v);
|
1041
|
-
if (np ==
|
1063
|
+
if (np == nullptr) { fhold; fbreak; } else { fexec np; }
|
1042
1064
|
}
|
1043
1065
|
|
1044
1066
|
main := begin_meta (
|
@@ -1065,7 +1087,7 @@ const char* edn::Parser::parse_meta(const char *p, const char *pe)
|
|
1065
1087
|
}
|
1066
1088
|
else if (cs == EDN_meta_en_main) {} // silence ragel warning
|
1067
1089
|
|
1068
|
-
return
|
1090
|
+
return nullptr;
|
1069
1091
|
}
|
1070
1092
|
|
1071
1093
|
|
@@ -1086,7 +1108,7 @@ const char* edn::Parser::parse_meta(const char *p, const char *pe)
|
|
1086
1108
|
// an actual data item
|
1087
1109
|
std::size_t meta_sz = meta_size();
|
1088
1110
|
const char* np = parse_value(fpc, pe, result);
|
1089
|
-
if (np ==
|
1111
|
+
if (np == nullptr) { fexec pe; fbreak; } else {
|
1090
1112
|
// if we have metadata saved and it matches the count we
|
1091
1113
|
// saved before we parsed a value, then we must bind the
|
1092
1114
|
// metadata sequence to it
|
@@ -1120,7 +1142,7 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
1120
1142
|
return EDN_EOF_CONST;
|
1121
1143
|
}
|
1122
1144
|
else if (cs == EDN_parser_first_final) {
|
1123
|
-
p = pe = eof =
|
1145
|
+
p = pe = eof = nullptr;
|
1124
1146
|
}
|
1125
1147
|
else if (cs == EDN_parser_en_main) {} // silence ragel warning
|
1126
1148
|
return result;
|
@@ -1144,7 +1166,7 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
1144
1166
|
meta_sz = meta_size();
|
1145
1167
|
|
1146
1168
|
const char* np = parse_value(fpc, pe, value);
|
1147
|
-
if (np ==
|
1169
|
+
if (np == nullptr) { fhold; fbreak; } else {
|
1148
1170
|
if (!meta_empty()) {
|
1149
1171
|
// was an additional metadata entry read? if so, don't
|
1150
1172
|
// return a value
|
data/ext/edn_turbo/extconf.rb
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# The MIT License (MIT)
|
4
|
+
|
5
|
+
# Copyright (c) 2015-2019 Ed Porras
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
12
|
+
# furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
15
|
+
# all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
# THE SOFTWARE.
|
24
|
+
|
3
25
|
require 'mkmf'
|
4
26
|
|
5
27
|
header_dirs =
|
@@ -38,7 +60,8 @@ lib_dirs =
|
|
38
60
|
dir_config('icuuc', header_dirs, lib_dirs)
|
39
61
|
|
40
62
|
# feels very hackish to do this but the new icu4c needs it on MacOS
|
41
|
-
$CXXFLAGS << ' -stdlib=libc++ -
|
63
|
+
$CXXFLAGS << ' -stdlib=libc++ -Wno-deprecated-register' if RUBY_PLATFORM =~ /darwin/
|
64
|
+
$CXXFLAGS << ' -std=c++11 -std=gnu++11'
|
42
65
|
|
43
66
|
abort "\n>> failed to find icu4c headers - is icu4c installed?\n\n" unless
|
44
67
|
find_header('unicode/uversion.h')
|
data/ext/edn_turbo/main.cc
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
// The MIT License (MIT)
|
2
|
+
|
3
|
+
// Copyright (c) 2015-2019 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 <signal.h>
|
2
24
|
#include <iostream>
|
3
25
|
#include <clocale>
|
@@ -10,150 +32,147 @@
|
|
10
32
|
|
11
33
|
namespace edn {
|
12
34
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
35
|
+
VALUE rb_mEDN;
|
36
|
+
VALUE rb_mEDNT;
|
37
|
+
|
38
|
+
// Symbols used to call into the ruby world.
|
39
|
+
VALUE EDN_MAKE_SYMBOL_METHOD = Qnil;
|
40
|
+
VALUE EDN_MAKE_LIST_METHOD = Qnil;
|
41
|
+
VALUE EDN_MAKE_SET_METHOD = Qnil;
|
42
|
+
VALUE EDN_MAKE_BIG_DECIMAL_METHOD = Qnil;
|
43
|
+
VALUE EDN_TAGGED_ELEM_METHOD = Qnil;
|
44
|
+
VALUE EDNT_EXTENDED_VALUE_METHOD = Qnil;
|
45
|
+
|
46
|
+
VALUE RUBY_STRING_TO_I_METHOD = Qnil;
|
47
|
+
VALUE RUBY_STRING_TO_F_METHOD = Qnil;
|
48
|
+
VALUE RUBY_READ_METHOD = Qnil;
|
49
|
+
|
50
|
+
// returned when EOF - defined as a constant in EDN module
|
51
|
+
VALUE EDN_EOF_CONST = Qnil;
|
52
|
+
|
53
|
+
//
|
54
|
+
// Wrappers to hook the class w/ the C-api.
|
55
|
+
static void delete_parser(void* p_ptr) {
|
56
|
+
delete reinterpret_cast<edn::Parser*>(p_ptr);
|
57
|
+
}
|
58
|
+
|
59
|
+
static const rb_data_type_t parser_data_type = {
|
60
|
+
"edn_turbo::Parser",
|
61
|
+
{0, delete_parser, 0, {0}},
|
62
|
+
0, 0,
|
63
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
64
|
+
};
|
65
|
+
|
66
|
+
static VALUE wrap_parser_ptr(VALUE klass, edn::Parser* ptr) {
|
67
|
+
return TypedData_Wrap_Struct(klass, &parser_data_type, ptr);
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE alloc_obj(VALUE self){
|
71
|
+
return wrap_parser_ptr(self, new Parser());
|
72
|
+
}
|
73
|
+
|
74
|
+
static inline Parser* get_parser(VALUE self)
|
75
|
+
{
|
76
|
+
Parser *p;
|
77
|
+
TypedData_Get_Struct( self, edn::Parser, &parser_data_type, p );
|
78
|
+
return p;
|
79
|
+
}
|
80
|
+
static VALUE set_source(VALUE self, VALUE data);
|
81
|
+
|
82
|
+
//
|
83
|
+
// Called by the constructor - sets the source if passed.
|
84
|
+
static VALUE initialize(int argc, VALUE* argv, VALUE self)
|
85
|
+
{
|
86
|
+
if (argc > 0) {
|
87
|
+
set_source( self, argv[0] );
|
88
|
+
}
|
89
|
+
return self;
|
90
|
+
}
|
91
|
+
|
92
|
+
//
|
93
|
+
// change the input source
|
94
|
+
static VALUE set_source(VALUE self, VALUE data)
|
95
|
+
{
|
96
|
+
Parser* p = get_parser(self);
|
97
|
+
|
98
|
+
switch (TYPE(data))
|
99
|
+
{
|
100
|
+
case T_STRING:
|
101
|
+
{
|
80
102
|
const char* stream = StringValueCStr(data);
|
81
103
|
if (stream) {
|
82
|
-
|
104
|
+
p->set_source( stream, std::strlen(stream) );
|
83
105
|
}
|
84
106
|
break;
|
85
|
-
|
86
|
-
|
87
|
-
|
107
|
+
}
|
108
|
+
case T_FILE:
|
109
|
+
{
|
88
110
|
// extract the stream pointer
|
89
111
|
rb_io_t* fptr = RFILE(data)->fptr;
|
90
112
|
if (!fptr) {
|
91
|
-
|
113
|
+
rb_raise(rb_eRuntimeError, "Ruby IO - fptr is null");
|
92
114
|
}
|
93
115
|
|
94
116
|
rb_io_check_char_readable(fptr);
|
95
117
|
|
96
118
|
FILE* fp = rb_io_stdio_file(fptr);
|
97
119
|
if (!fp) {
|
98
|
-
|
120
|
+
rb_raise(rb_eRuntimeError, "Ruby IO - fptr->fp is null");
|
99
121
|
}
|
100
122
|
|
101
123
|
p->set_source(fp);
|
102
124
|
break;
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
// StringIO or some other IO not part of the ruby core
|
107
|
-
// this is very inefficient as it'll require read()
|
108
|
-
// calls from the ruby side (involves a lot of data
|
109
|
-
// wrapping, etc)
|
125
|
+
}
|
126
|
+
case T_DATA:
|
127
|
+
{
|
128
|
+
// StringIO or some other IO not part of the ruby core
|
110
129
|
if (rb_respond_to(data, RUBY_READ_METHOD)) {
|
111
|
-
|
112
|
-
|
130
|
+
p->set_source(data);
|
131
|
+
break;
|
113
132
|
}
|
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
|
-
|
133
|
+
}
|
134
|
+
default:
|
135
|
+
rb_raise(rb_eArgError, "set_source expected String, core IO, or IO that responds to read()");
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
|
139
|
+
return self;
|
140
|
+
}
|
141
|
+
|
142
|
+
//
|
143
|
+
// eof?
|
144
|
+
static VALUE eof(VALUE self, VALUE data)
|
145
|
+
{
|
146
|
+
return get_parser(self)->is_eof();
|
147
|
+
}
|
148
|
+
|
149
|
+
//
|
150
|
+
// parses an entire stream
|
151
|
+
static VALUE read(VALUE self, VALUE data)
|
152
|
+
{
|
153
|
+
if (TYPE(data) != T_STRING) {
|
154
|
+
rb_raise(rb_eTypeError, "Expected String data");
|
155
|
+
}
|
156
|
+
const char* stream = StringValueCStr(data);
|
157
|
+
if (stream) {
|
158
|
+
return get_parser(self)->parse(stream, std::strlen(stream) );
|
159
|
+
}
|
160
|
+
return Qnil;
|
161
|
+
}
|
162
|
+
|
163
|
+
//
|
164
|
+
// gets the next token in the current stream
|
165
|
+
static VALUE next(VALUE self, VALUE data)
|
166
|
+
{
|
167
|
+
return get_parser(self)->next();
|
168
|
+
}
|
169
|
+
|
170
|
+
//
|
171
|
+
// signal handler
|
172
|
+
[[noreturn]] static void die(int sig)
|
173
|
+
{
|
174
|
+
exit(-1);
|
175
|
+
}
|
157
176
|
}
|
158
177
|
|
159
178
|
|
@@ -162,45 +181,49 @@ namespace edn {
|
|
162
181
|
extern "C"
|
163
182
|
void Init_edn_turbo(void)
|
164
183
|
{
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
184
|
+
struct sigaction a;
|
185
|
+
a.sa_handler = edn::die;
|
186
|
+
sigemptyset(&a.sa_mask);
|
187
|
+
a.sa_flags = 0;
|
188
|
+
sigaction(SIGINT, &a, nullptr);
|
189
|
+
|
190
|
+
// pass things back as utf-8
|
191
|
+
if (!setlocale( LC_ALL, "" )) {
|
192
|
+
rb_raise(rb_eRuntimeError, "Extension init error calling setlocale() - It appears your system's locale is not configured correctly.\n");
|
193
|
+
}
|
194
|
+
|
195
|
+
edn::rb_mEDN = rb_const_get(rb_cObject, rb_intern("EDN"));
|
196
|
+
edn::rb_mEDNT = rb_define_module("EDNT");
|
197
|
+
|
198
|
+
// bind the ruby Parser class to the C++ one
|
199
|
+
VALUE rb_cParser = rb_define_class_under(edn::rb_mEDNT, "Parser", rb_cObject);
|
200
|
+
rb_define_alloc_func(rb_cParser, edn::alloc_obj);
|
201
|
+
rb_define_method(rb_cParser, "initialize",
|
202
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::initialize), -1 );
|
203
|
+
rb_define_method(rb_cParser, "ext_eof",
|
204
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::eof), 0 );
|
205
|
+
rb_define_method(rb_cParser, "set_input",
|
206
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::set_source), 1 );
|
207
|
+
rb_define_method(rb_cParser, "parse",
|
208
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::read), 1 );
|
209
|
+
rb_define_method(rb_cParser, "read",
|
210
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::next), 0 );
|
211
|
+
|
212
|
+
// bind ruby methods we'll call - these should be defined in edn_turbo.rb
|
213
|
+
edn::EDN_MAKE_SYMBOL_METHOD = rb_intern("symbol");
|
214
|
+
edn::EDN_MAKE_LIST_METHOD = rb_intern("list");
|
215
|
+
edn::EDN_MAKE_SET_METHOD = rb_intern("set");
|
216
|
+
edn::EDN_MAKE_BIG_DECIMAL_METHOD = rb_intern("big_decimal");
|
217
|
+
edn::EDN_TAGGED_ELEM_METHOD = rb_intern("tagged_element");
|
218
|
+
|
219
|
+
// defined in EDNT - see edn_parser.rb
|
220
|
+
edn::EDNT_EXTENDED_VALUE_METHOD = rb_intern("extend_for_meta");
|
221
|
+
|
222
|
+
// ruby methods
|
223
|
+
edn::RUBY_STRING_TO_I_METHOD = rb_intern("to_i");
|
224
|
+
edn::RUBY_STRING_TO_F_METHOD = rb_intern("to_f");
|
225
|
+
edn::RUBY_READ_METHOD = rb_intern("read");
|
226
|
+
|
227
|
+
// so we can return EOF directly
|
228
|
+
edn::EDN_EOF_CONST = rb_const_get(edn::rb_mEDN, rb_intern("EOF"));
|
206
229
|
}
|