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/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-2021 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,20 @@ 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
|
-
|
63
|
+
if RUBY_PLATFORM =~ /darwin/
|
64
|
+
$CXXFLAGS << ' -stdlib=libc++ -Wno-deprecated-register'
|
65
|
+
else
|
66
|
+
# remove some flags that are either clang-specific or unrecognized
|
67
|
+
# but somehow get passed under linux (?!)
|
68
|
+
%w[
|
69
|
+
-Wno-self-assign -Wno-parentheses-equality -Wno-constant-logical-operand
|
70
|
+
-Wno-cast-function-type -Wdeclaration-after-statement -Wimplicit-function-declaration
|
71
|
+
-Wimplicit-int
|
72
|
+
].each do |f|
|
73
|
+
$warnflags.sub!(f, '')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
$CXXFLAGS << ' -std=c++11 -std=gnu++11'
|
42
77
|
|
43
78
|
abort "\n>> failed to find icu4c headers - is icu4c installed?\n\n" unless
|
44
79
|
find_header('unicode/uversion.h')
|
data/ext/edn_turbo/main.cc
CHANGED
@@ -1,159 +1,183 @@
|
|
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 <signal.h>
|
2
24
|
#include <iostream>
|
3
25
|
#include <clocale>
|
4
26
|
#include <cstring>
|
5
27
|
|
6
28
|
#include <ruby/ruby.h>
|
29
|
+
#include <ruby/version.h>
|
7
30
|
#include <ruby/io.h>
|
8
31
|
|
9
32
|
#include "parser.h"
|
10
33
|
|
11
34
|
namespace edn {
|
12
35
|
|
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
|
-
|
36
|
+
VALUE rb_mEDN;
|
37
|
+
VALUE rb_mEDNT;
|
38
|
+
|
39
|
+
// Symbols used to call into the ruby world.
|
40
|
+
VALUE EDN_MAKE_SYMBOL_METHOD = Qnil;
|
41
|
+
VALUE EDN_MAKE_LIST_METHOD = Qnil;
|
42
|
+
VALUE EDN_MAKE_SET_METHOD = Qnil;
|
43
|
+
VALUE EDN_MAKE_BIG_DECIMAL_METHOD = Qnil;
|
44
|
+
VALUE EDN_MAKE_RATIONAL_METHOD = Qnil;
|
45
|
+
VALUE EDN_TAGGED_ELEM_METHOD = Qnil;
|
46
|
+
VALUE EDNT_EXTENDED_VALUE_METHOD = Qnil;
|
47
|
+
|
48
|
+
VALUE RUBY_STRING_TO_I_METHOD = Qnil;
|
49
|
+
VALUE RUBY_STRING_TO_F_METHOD = Qnil;
|
50
|
+
VALUE RUBY_READ_METHOD = Qnil;
|
51
|
+
|
52
|
+
VALUE RUBY_NAN_CONST = Qnil;
|
53
|
+
VALUE RUBY_INF_CONST = Qnil;
|
54
|
+
|
55
|
+
// returned when EOF - defined as a constant in EDN module
|
56
|
+
VALUE EDN_EOF_CONST = Qnil;
|
57
|
+
|
58
|
+
//
|
59
|
+
// Wrappers to hook the class w/ the C-api.
|
60
|
+
static void delete_parser(void* p_ptr) {
|
61
|
+
delete reinterpret_cast<edn::Parser*>(p_ptr);
|
62
|
+
}
|
63
|
+
|
64
|
+
static const rb_data_type_t parser_data_type = {
|
65
|
+
"edn_turbo::Parser",
|
66
|
+
{0, delete_parser, 0, 0},
|
67
|
+
0, 0,
|
68
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
69
|
+
};
|
70
|
+
|
71
|
+
static VALUE wrap_parser_ptr(VALUE klass, edn::Parser* ptr) {
|
72
|
+
return TypedData_Wrap_Struct(klass, &parser_data_type, ptr);
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE alloc_obj(VALUE self){
|
76
|
+
return wrap_parser_ptr(self, new Parser());
|
77
|
+
}
|
78
|
+
|
79
|
+
static inline Parser* get_parser(VALUE self)
|
80
|
+
{
|
81
|
+
Parser *p;
|
82
|
+
TypedData_Get_Struct( self, edn::Parser, &parser_data_type, p );
|
83
|
+
return p;
|
84
|
+
}
|
85
|
+
static VALUE set_source(VALUE self, VALUE data);
|
86
|
+
|
87
|
+
//
|
88
|
+
// Called by the constructor - sets the source if passed.
|
89
|
+
static VALUE initialize(int argc, VALUE* argv, VALUE self)
|
90
|
+
{
|
91
|
+
if (argc > 0) {
|
92
|
+
set_source( self, argv[0] );
|
93
|
+
}
|
94
|
+
return self;
|
95
|
+
}
|
96
|
+
|
97
|
+
//
|
98
|
+
// change the input source
|
99
|
+
static VALUE set_source(VALUE self, VALUE data)
|
100
|
+
{
|
101
|
+
Parser* p = get_parser(self);
|
102
|
+
|
103
|
+
switch (TYPE(data))
|
104
|
+
{
|
105
|
+
case T_STRING:
|
106
|
+
{
|
80
107
|
const char* stream = StringValueCStr(data);
|
81
108
|
if (stream) {
|
82
|
-
|
109
|
+
p->set_source( stream, std::strlen(stream) );
|
83
110
|
}
|
84
111
|
break;
|
85
|
-
|
86
|
-
|
87
|
-
|
112
|
+
}
|
113
|
+
case T_FILE:
|
114
|
+
{
|
88
115
|
// extract the stream pointer
|
89
116
|
rb_io_t* fptr = RFILE(data)->fptr;
|
90
117
|
if (!fptr) {
|
91
|
-
|
118
|
+
rb_raise(rb_eRuntimeError, "Ruby IO - fptr is null");
|
92
119
|
}
|
93
120
|
|
94
121
|
rb_io_check_char_readable(fptr);
|
95
122
|
|
96
123
|
FILE* fp = rb_io_stdio_file(fptr);
|
97
124
|
if (!fp) {
|
98
|
-
|
125
|
+
rb_raise(rb_eRuntimeError, "Ruby IO - fptr->fp is null");
|
99
126
|
}
|
100
127
|
|
101
128
|
p->set_source(fp);
|
102
129
|
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)
|
130
|
+
}
|
131
|
+
case T_DATA:
|
132
|
+
{
|
133
|
+
// StringIO or some other IO not part of the ruby core
|
110
134
|
if (rb_respond_to(data, RUBY_READ_METHOD)) {
|
111
|
-
|
112
|
-
|
135
|
+
p->set_source(data);
|
136
|
+
break;
|
113
137
|
}
|
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
|
-
|
138
|
+
}
|
139
|
+
default:
|
140
|
+
rb_raise(rb_eArgError, "set_source expected String, core IO, or IO that responds to read()");
|
141
|
+
break;
|
142
|
+
}
|
143
|
+
|
144
|
+
return self;
|
145
|
+
}
|
146
|
+
|
147
|
+
//
|
148
|
+
// eof?
|
149
|
+
static VALUE eof(VALUE self, VALUE data)
|
150
|
+
{
|
151
|
+
return get_parser(self)->is_eof();
|
152
|
+
}
|
153
|
+
|
154
|
+
//
|
155
|
+
// parses an entire stream
|
156
|
+
static VALUE read(VALUE self, VALUE data)
|
157
|
+
{
|
158
|
+
if (TYPE(data) != T_STRING) {
|
159
|
+
rb_raise(rb_eTypeError, "Expected String data");
|
160
|
+
}
|
161
|
+
const char* stream = StringValueCStr(data);
|
162
|
+
if (stream) {
|
163
|
+
return get_parser(self)->parse(stream, std::strlen(stream) );
|
164
|
+
}
|
165
|
+
return Qnil;
|
166
|
+
}
|
167
|
+
|
168
|
+
//
|
169
|
+
// gets the next token in the current stream
|
170
|
+
static VALUE next(VALUE self, VALUE data)
|
171
|
+
{
|
172
|
+
return get_parser(self)->next();
|
173
|
+
}
|
174
|
+
|
175
|
+
//
|
176
|
+
// signal handler
|
177
|
+
[[noreturn]] static void die(int sig)
|
178
|
+
{
|
179
|
+
exit(-1);
|
180
|
+
}
|
157
181
|
}
|
158
182
|
|
159
183
|
|
@@ -162,45 +186,56 @@ namespace edn {
|
|
162
186
|
extern "C"
|
163
187
|
void Init_edn_turbo(void)
|
164
188
|
{
|
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
|
-
|
189
|
+
struct sigaction a;
|
190
|
+
a.sa_handler = edn::die;
|
191
|
+
sigemptyset(&a.sa_mask);
|
192
|
+
a.sa_flags = 0;
|
193
|
+
sigaction(SIGINT, &a, nullptr);
|
194
|
+
|
195
|
+
// pass things back as utf-8
|
196
|
+
if (!setlocale( LC_ALL, "" )) {
|
197
|
+
rb_raise(rb_eRuntimeError, "Extension init error calling setlocale() - It appears your system's locale is not configured correctly.\n");
|
198
|
+
}
|
199
|
+
|
200
|
+
edn::rb_mEDN = rb_const_get(rb_cObject, rb_intern("EDN"));
|
201
|
+
edn::rb_mEDNT = rb_define_module("EDNT");
|
202
|
+
|
203
|
+
// bind the ruby Parser class to the C++ one
|
204
|
+
VALUE rb_cParser = rb_define_class_under(edn::rb_mEDNT, "Parser", rb_cObject);
|
205
|
+
rb_define_alloc_func(rb_cParser, edn::alloc_obj);
|
206
|
+
rb_define_method(rb_cParser, "initialize",
|
207
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::initialize), -1 );
|
208
|
+
rb_define_method(rb_cParser, "ext_eof",
|
209
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::eof), 0 );
|
210
|
+
rb_define_method(rb_cParser, "set_input",
|
211
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::set_source), 1 );
|
212
|
+
rb_define_method(rb_cParser, "parse",
|
213
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::read), 1 );
|
214
|
+
rb_define_method(rb_cParser, "read",
|
215
|
+
reinterpret_cast<VALUE(*)(ANYARGS)>(&edn::next), 0 );
|
216
|
+
|
217
|
+
// bind edn-ruby methods we'll call
|
218
|
+
edn::EDN_MAKE_SYMBOL_METHOD = rb_intern("symbol");
|
219
|
+
edn::EDN_MAKE_LIST_METHOD = rb_intern("list");
|
220
|
+
edn::EDN_MAKE_SET_METHOD = rb_intern("set");
|
221
|
+
edn::EDN_TAGGED_ELEM_METHOD = rb_intern("tagged_element");
|
222
|
+
|
223
|
+
// see lib/edn_turbo.rb
|
224
|
+
edn::EDN_MAKE_BIG_DECIMAL_METHOD = rb_intern("big_decimal_edn_turbo");
|
225
|
+
|
226
|
+
// defined in EDNT - see edn_parser.rb
|
227
|
+
edn::EDNT_EXTENDED_VALUE_METHOD = rb_intern("extend_for_meta");
|
228
|
+
edn::EDN_MAKE_RATIONAL_METHOD = rb_intern("rational"); // should be in edn-ruby
|
229
|
+
|
230
|
+
// ruby methods
|
231
|
+
edn::RUBY_STRING_TO_I_METHOD = rb_intern("to_i");
|
232
|
+
edn::RUBY_STRING_TO_F_METHOD = rb_intern("to_f");
|
233
|
+
edn::RUBY_READ_METHOD = rb_intern("read");
|
234
|
+
|
235
|
+
VALUE rb_mFloat = rb_const_get(rb_cObject, rb_intern("Float"));
|
236
|
+
edn::RUBY_NAN_CONST = rb_const_get(rb_mFloat, rb_intern("NAN"));
|
237
|
+
edn::RUBY_INF_CONST = rb_const_get(rb_mFloat, rb_intern("INFINITY"));
|
238
|
+
|
239
|
+
// so we can return EOF directly
|
240
|
+
edn::EDN_EOF_CONST = rb_const_get(edn::rb_mEDN, rb_intern("EOF"));
|
206
241
|
}
|