edn_turbo 0.3.0 → 0.3.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 +4 -4
- data/LICENSE +21 -0
- data/bin/ppedn +24 -3
- data/ext/edn_turbo/edn_parser.cc +524 -318
- data/ext/edn_turbo/edn_parser.h +21 -7
- data/ext/edn_turbo/edn_parser.rl +126 -29
- data/ext/edn_turbo/edn_parser_util.cc +70 -16
- data/ext/edn_turbo/main.cc +21 -11
- data/lib/edn_turbo/edn_parser.rb +2 -1
- data/lib/edn_turbo/version.rb +2 -2
- data/lib/edn_turbo.rb +30 -0
- data/test/test_output_diff.rb +28 -1
- metadata +4 -3
data/ext/edn_turbo/edn_parser.h
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
#ifndef
|
2
|
-
#define
|
1
|
+
#ifndef EDN_RAGEL_PARSER_H
|
2
|
+
#define EDN_RAGEL_PARSER_H
|
3
3
|
|
4
4
|
#include <string>
|
5
5
|
#include <sstream>
|
6
|
-
#include <
|
6
|
+
#include <vector>
|
7
7
|
|
8
8
|
#include <ruby/ruby.h>
|
9
9
|
|
@@ -14,8 +14,10 @@ namespace edn
|
|
14
14
|
extern VALUE EDNT_MAKE_EDN_SYMBOL;
|
15
15
|
extern VALUE EDNT_MAKE_SET_METHOD;
|
16
16
|
extern VALUE EDNT_TAGGED_ELEM;
|
17
|
+
extern VALUE EDNT_BIND_META_TO_VALUE;
|
17
18
|
extern VALUE EDNT_STR_INT_TO_BIGNUM;
|
18
19
|
extern VALUE EDNT_STR_DBL_TO_BIGNUM;
|
20
|
+
extern VALUE EDNT_EOF;
|
19
21
|
|
20
22
|
//
|
21
23
|
// C-extension EDN Parser class representation
|
@@ -24,11 +26,15 @@ namespace edn
|
|
24
26
|
public:
|
25
27
|
Parser() : p(NULL), pe(NULL), eof(NULL), line_number(1) { }
|
26
28
|
|
29
|
+
// change input source
|
27
30
|
void set_source(const char* src, std::size_t len);
|
28
31
|
|
29
|
-
bool is_eof() const { return (p
|
32
|
+
bool is_eof() const { return (p == eof); }
|
33
|
+
|
34
|
+
// parses an entire stream
|
30
35
|
VALUE parse(const char* s, std::size_t len);
|
31
|
-
|
36
|
+
|
37
|
+
// returns the next element in the current stream
|
32
38
|
VALUE next();
|
33
39
|
|
34
40
|
static void throw_error(int error);
|
@@ -39,9 +45,10 @@ namespace edn
|
|
39
45
|
const char* pe;
|
40
46
|
const char* eof;
|
41
47
|
std::size_t line_number;
|
42
|
-
std::
|
48
|
+
std::vector<VALUE> discard;
|
49
|
+
std::vector<VALUE> metadata;
|
43
50
|
|
44
|
-
void
|
51
|
+
void reset_state();
|
45
52
|
|
46
53
|
const char* parse_value (const char *p, const char *pe, VALUE& v);
|
47
54
|
const char* parse_string (const char *p, const char *pe, VALUE& v);
|
@@ -58,6 +65,9 @@ namespace edn
|
|
58
65
|
const char* parse_set (const char *p, const char *pe, VALUE& v);
|
59
66
|
const char* parse_discard (const char *p, const char *pe);
|
60
67
|
const char* parse_tagged (const char *p, const char *pe, VALUE& v);
|
68
|
+
const char* parse_meta (const char *p, const char *pe);
|
69
|
+
|
70
|
+
bool parse_next(VALUE& value);
|
61
71
|
|
62
72
|
// defined in edn_parser_unicode.cc
|
63
73
|
static bool to_utf8(const char *s, std::size_t len, std::string& rslt);
|
@@ -73,6 +83,10 @@ namespace edn
|
|
73
83
|
static VALUE make_ruby_set(VALUE elems);
|
74
84
|
static VALUE tagged_element(VALUE name, VALUE data);
|
75
85
|
|
86
|
+
// metadata
|
87
|
+
VALUE ruby_meta();
|
88
|
+
VALUE bind_meta_to_value(VALUE value);
|
89
|
+
|
76
90
|
// utility method to convert a primitive in string form to a
|
77
91
|
// ruby type
|
78
92
|
template <class T>
|
data/ext/edn_turbo/edn_parser.rl
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#include <iostream>
|
2
2
|
#include <string>
|
3
|
-
#include <
|
3
|
+
#include <vector>
|
4
4
|
#include <exception>
|
5
5
|
|
6
6
|
#include "edn_parser.h"
|
@@ -25,18 +25,19 @@
|
|
25
25
|
|
26
26
|
operators = [/\.\*!_\?$%&<>\=+\-];
|
27
27
|
symbol_start = alpha;
|
28
|
-
symbol_chars = symbol_start | digit | [\#:_
|
28
|
+
symbol_chars = symbol_start | digit | [\#:_\-\.\'];
|
29
29
|
|
30
30
|
begin_dispatch = '#';
|
31
31
|
begin_keyword = ':';
|
32
32
|
begin_char = '\\';
|
33
|
-
begin_value = alnum | [:\"\{\[\(\\\#] | operators;
|
34
|
-
begin_symbol = symbol_start;
|
35
33
|
begin_vector = '[';
|
36
34
|
begin_map = '{';
|
37
35
|
begin_list = '(';
|
36
|
+
begin_meta = '^';
|
38
37
|
string_delim = '"';
|
39
38
|
begin_number = digit;
|
39
|
+
begin_value = alnum | [:\"\{\[\(\\\#^] | operators;
|
40
|
+
begin_symbol = symbol_start;
|
40
41
|
|
41
42
|
symbol_name = symbol_start (symbol_chars)*;
|
42
43
|
symbol = (symbol_name ('/' symbol_name)?);
|
@@ -145,6 +146,12 @@
|
|
145
146
|
if (np == NULL) { fhold; fbreak; } else fexec np;
|
146
147
|
}
|
147
148
|
|
149
|
+
action parse_meta {
|
150
|
+
// ^
|
151
|
+
const char *np = parse_meta(fpc, pe);
|
152
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
153
|
+
}
|
154
|
+
|
148
155
|
action parse_dispatch {
|
149
156
|
// handles tokens w/ leading # ("#_", "#{", and tagged elems)
|
150
157
|
const char *np = parse_dispatch(fpc + 1, pe, v);
|
@@ -162,6 +169,7 @@
|
|
162
169
|
begin_vector >parse_vector |
|
163
170
|
begin_list >parse_list |
|
164
171
|
begin_map >parse_map |
|
172
|
+
begin_meta >parse_meta |
|
165
173
|
begin_dispatch >parse_dispatch
|
166
174
|
) %*exit;
|
167
175
|
}%%
|
@@ -223,7 +231,6 @@ const char *edn::Parser::parse_value(const char *p, const char *pe, VALUE& v)
|
|
223
231
|
|
224
232
|
const char* edn::Parser::parse_string(const char *p, const char *pe, VALUE& v)
|
225
233
|
{
|
226
|
-
// std::cerr << __FUNCTION__ << " - p: '" << p << "'" << std::endl;
|
227
234
|
static const char* EDN_TYPE = "string";
|
228
235
|
int cs;
|
229
236
|
bool encode = false;
|
@@ -551,7 +558,7 @@ const char* edn::Parser::parse_symbol(const char *p, const char *pe, VALUE& s)
|
|
551
558
|
// object is not meant to be kept due to a #_ so don't
|
552
559
|
// push it into the list of elements
|
553
560
|
if (!discard.empty()) {
|
554
|
-
discard.
|
561
|
+
discard.pop_back();
|
555
562
|
}
|
556
563
|
else {
|
557
564
|
// otherwise we add it to the list of elements for the
|
@@ -834,17 +841,23 @@ const char* edn::Parser::parse_set(const char *p, const char *pe, VALUE& v)
|
|
834
841
|
// this token is to be discard it so store it in the
|
835
842
|
// discard stack - we really don't need to save it so this
|
836
843
|
// could be simplified
|
837
|
-
discard.
|
844
|
+
discard.push_back(v);
|
838
845
|
fexec np;
|
839
846
|
} else {
|
840
847
|
fhold; fbreak;
|
841
848
|
}
|
842
849
|
}
|
843
850
|
|
851
|
+
action discard_err {
|
852
|
+
std::stringstream s;
|
853
|
+
s << "discard sequence without element to discard";
|
854
|
+
error(__FUNCTION__, s.str());
|
855
|
+
fhold; fbreak;
|
856
|
+
}
|
844
857
|
|
845
858
|
main := begin_discard ignore* (
|
846
859
|
begin_value >discard_value
|
847
|
-
) @exit;
|
860
|
+
) @err(discard_err) @exit;
|
848
861
|
}%%
|
849
862
|
|
850
863
|
|
@@ -942,6 +955,51 @@ const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
|
942
955
|
|
943
956
|
|
944
957
|
|
958
|
+
// ============================================================
|
959
|
+
// metadata - looks like ruby just discards this but we'll track it
|
960
|
+
// and provide a means to retrive after each parse op - might be
|
961
|
+
// useful?
|
962
|
+
//
|
963
|
+
%%{
|
964
|
+
machine EDN_meta;
|
965
|
+
include EDN_common;
|
966
|
+
|
967
|
+
write data;
|
968
|
+
|
969
|
+
action parse_meta {
|
970
|
+
const char *np = parse_value(fpc, pe, v);
|
971
|
+
if (np) { fexec np; } else { fhold; fbreak; }
|
972
|
+
}
|
973
|
+
|
974
|
+
main := begin_meta (
|
975
|
+
begin_value >parse_meta
|
976
|
+
) @exit;
|
977
|
+
}%%
|
978
|
+
|
979
|
+
|
980
|
+
const char* edn::Parser::parse_meta(const char *p, const char *pe)
|
981
|
+
{
|
982
|
+
int cs;
|
983
|
+
VALUE v;
|
984
|
+
|
985
|
+
%% write init;
|
986
|
+
%% write exec;
|
987
|
+
|
988
|
+
if (cs >= EDN_meta_first_final) {
|
989
|
+
metadata.push_back(v);
|
990
|
+
return p + 1;
|
991
|
+
}
|
992
|
+
else if (cs == EDN_meta_error) {
|
993
|
+
error(__FUNCTION__, *p);
|
994
|
+
return pe;
|
995
|
+
}
|
996
|
+
else if (cs == EDN_meta_en_main) {} // silence ragel warning
|
997
|
+
|
998
|
+
return NULL;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
|
1002
|
+
|
945
1003
|
// ============================================================
|
946
1004
|
// parses entire input but expects single valid token at the
|
947
1005
|
// top-level, therefore, does not tokenize source stream
|
@@ -953,8 +1011,21 @@ const char* edn::Parser::parse_tagged(const char *p, const char *pe, VALUE& v)
|
|
953
1011
|
write data;
|
954
1012
|
|
955
1013
|
action parse_value {
|
1014
|
+
// save the count of metadata items before we parse this value
|
1015
|
+
// so we can determine if we've read another metadata value or
|
1016
|
+
// an actual data item
|
1017
|
+
std::size_t meta_size = metadata.size();
|
956
1018
|
const char* np = parse_value(fpc, pe, result);
|
957
|
-
if (np == NULL) { fexec pe; fbreak; } else
|
1019
|
+
if (np == NULL) { fexec pe; fbreak; } else {
|
1020
|
+
// if we have metadata saved and it matches the count we
|
1021
|
+
// saved before we parsed a value, then we must bind the
|
1022
|
+
// metadata sequence to it
|
1023
|
+
if (!metadata.empty() && metadata.size() == meta_size) {
|
1024
|
+
// this will empty the metadata sequence too
|
1025
|
+
result = bind_meta_to_value(result);
|
1026
|
+
}
|
1027
|
+
fexec np;
|
1028
|
+
}
|
958
1029
|
}
|
959
1030
|
|
960
1031
|
element = begin_value >parse_value;
|
@@ -970,23 +1041,17 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
970
1041
|
int cs;
|
971
1042
|
VALUE result = Qnil;
|
972
1043
|
|
973
|
-
// reset line counter & discard stack
|
974
|
-
reset();
|
975
|
-
|
976
1044
|
%% write init;
|
977
|
-
|
978
|
-
pe = p + len;
|
979
|
-
eof = pe;
|
1045
|
+
set_source(src, len);
|
980
1046
|
%% write exec;
|
981
1047
|
|
982
1048
|
if (cs == EDN_parser_error) {
|
983
|
-
|
984
|
-
|
1049
|
+
if (p)
|
1050
|
+
error(__FUNCTION__, *p);
|
1051
|
+
return EDNT_EOF;
|
985
1052
|
}
|
986
1053
|
else if (cs == EDN_parser_first_final) {
|
987
|
-
// whole source is parsed so reset
|
988
1054
|
p = pe = eof = NULL;
|
989
|
-
reset();
|
990
1055
|
}
|
991
1056
|
else if (cs == EDN_parser_en_main) {} // silence ragel warning
|
992
1057
|
return result;
|
@@ -1000,32 +1065,64 @@ VALUE edn::Parser::parse(const char* src, std::size_t len)
|
|
1000
1065
|
machine EDN_tokens;
|
1001
1066
|
include EDN_common;
|
1002
1067
|
|
1003
|
-
write data
|
1068
|
+
write data nofinal;
|
1004
1069
|
|
1005
1070
|
action parse_value {
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1071
|
+
// we won't know if we've parsed a discard or a metadata until
|
1072
|
+
// after parse_value() is done. Save the current number of
|
1073
|
+
// elements in the metadata sequence; then we can check if it
|
1074
|
+
// grew or if the discard sequence grew
|
1075
|
+
meta_size = metadata.size();
|
1009
1076
|
|
1010
|
-
|
1077
|
+
const char* np = parse_value(fpc, pe, value);
|
1078
|
+
|
1079
|
+
if (np == NULL) { fhold; fbreak; } else {
|
1080
|
+
if (metadata.size() > 0) {
|
1081
|
+
// was anotheran additional metadata entry read? if
|
1082
|
+
// so, don't return a value
|
1083
|
+
if (metadata.size() > meta_size) {
|
1084
|
+
is_value = false;
|
1085
|
+
}
|
1086
|
+
else {
|
1087
|
+
// a value was read and there's a pending metadata
|
1088
|
+
// sequence. Bind them.
|
1089
|
+
value = bind_meta_to_value(value);
|
1090
|
+
}
|
1091
|
+
} else if (!discard.empty()) {
|
1092
|
+
// a discard read. Don't return a value
|
1093
|
+
is_value = false;
|
1094
|
+
}
|
1095
|
+
fexec np;
|
1096
|
+
}
|
1097
|
+
}
|
1011
1098
|
|
1012
|
-
main := ignore*
|
1099
|
+
main := ignore* begin_value >parse_value ignore*;
|
1013
1100
|
}%%
|
1014
1101
|
|
1015
1102
|
|
1016
1103
|
//
|
1017
1104
|
//
|
1018
|
-
|
1105
|
+
bool edn::Parser::parse_next(VALUE& value)
|
1019
1106
|
{
|
1020
|
-
VALUE result = Qnil;
|
1021
1107
|
int cs;
|
1108
|
+
bool is_value = true;
|
1109
|
+
// need to track metadada read and bind it to the next value read
|
1110
|
+
// - but must account for sequences of metadata values
|
1111
|
+
std::size_t meta_size;
|
1112
|
+
|
1113
|
+
// clear any previously saved discards; only track if read during
|
1114
|
+
// this op
|
1115
|
+
discard.clear();
|
1022
1116
|
|
1023
1117
|
%% write init;
|
1024
1118
|
%% write exec;
|
1025
1119
|
|
1026
|
-
if (cs ==
|
1120
|
+
if (cs == EDN_parser_error) {
|
1121
|
+
value = EDNT_EOF;
|
1122
|
+
}
|
1123
|
+
else if (cs == EDN_tokens_en_main) {} // silence ragel warning
|
1027
1124
|
|
1028
|
-
return
|
1125
|
+
return is_value;
|
1029
1126
|
}
|
1030
1127
|
|
1031
1128
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
#include <iostream>
|
2
|
-
#include <iomanip>
|
3
2
|
#include <string>
|
4
3
|
#include <limits>
|
5
4
|
#include <exception>
|
@@ -26,20 +25,42 @@ namespace edn
|
|
26
25
|
|
27
26
|
|
28
27
|
// =================================================================
|
28
|
+
// for token-by-token parsing. If a discard or metadata is parsed,
|
29
|
+
// attempt to get the following value
|
30
|
+
//
|
31
|
+
VALUE Parser::next()
|
32
|
+
{
|
33
|
+
VALUE token = EDNT_EOF;
|
34
|
+
|
35
|
+
while (!is_eof())
|
36
|
+
{
|
37
|
+
// fetch a token. If it's metadata or discard
|
38
|
+
VALUE v;
|
39
|
+
if (parse_next(v))
|
40
|
+
{
|
41
|
+
// valid token
|
42
|
+
token = v;
|
43
|
+
break;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
return token;
|
48
|
+
}
|
49
|
+
|
29
50
|
// reset parsing state
|
30
51
|
//
|
31
|
-
void Parser::
|
52
|
+
void Parser::reset_state()
|
32
53
|
{
|
33
54
|
line_number = 1;
|
34
|
-
|
35
|
-
|
55
|
+
discard.clear();
|
56
|
+
metadata.clear();
|
36
57
|
}
|
37
58
|
|
38
59
|
//
|
39
60
|
// set a new source
|
40
61
|
void Parser::set_source(const char* src, std::size_t len)
|
41
62
|
{
|
42
|
-
|
63
|
+
reset_state();
|
43
64
|
// set ragel state
|
44
65
|
p = src;
|
45
66
|
pe = src + len;
|
@@ -55,16 +76,20 @@ namespace edn
|
|
55
76
|
|
56
77
|
// we're using at most 2 args
|
57
78
|
struct prot_args {
|
58
|
-
prot_args(ID m, VALUE arg) :
|
59
|
-
method(m), count(1) {
|
79
|
+
prot_args(ID r, ID m, VALUE arg) :
|
80
|
+
receiver(r), method(m), count(1) {
|
60
81
|
args[0] = arg;
|
61
82
|
}
|
62
|
-
prot_args(ID m, VALUE arg1, VALUE arg2) :
|
63
|
-
method(m), count(2) {
|
83
|
+
prot_args(ID r, ID m, VALUE arg1, VALUE arg2) :
|
84
|
+
receiver(r), method(m), count(2) {
|
64
85
|
args[0] = arg1;
|
65
86
|
args[1] = arg2;
|
66
87
|
}
|
67
88
|
|
89
|
+
VALUE call() const { return rb_funcall2( receiver, method, count, args ); }
|
90
|
+
|
91
|
+
private:
|
92
|
+
ID receiver;
|
68
93
|
ID method;
|
69
94
|
VALUE count;
|
70
95
|
VALUE args[2];
|
@@ -73,8 +98,10 @@ namespace edn
|
|
73
98
|
// this allows us to wrap with rb_protect()
|
74
99
|
static inline VALUE edn_wrap_funcall2( VALUE arg )
|
75
100
|
{
|
76
|
-
prot_args* a = reinterpret_cast<prot_args*>(arg);
|
77
|
-
|
101
|
+
const prot_args* a = reinterpret_cast<const prot_args*>(arg);
|
102
|
+
if (a)
|
103
|
+
return a->call();
|
104
|
+
return Qnil;
|
78
105
|
}
|
79
106
|
|
80
107
|
static inline VALUE edn_prot_rb_funcall( edn_rb_f_type func, VALUE args )
|
@@ -113,7 +140,7 @@ namespace edn
|
|
113
140
|
|
114
141
|
// value is outside of range of long type. Use ruby to convert it
|
115
142
|
VALUE rb_s = edn_prot_rb_new_str( str );
|
116
|
-
prot_args args(EDNT_STR_INT_TO_BIGNUM, rb_s);
|
143
|
+
prot_args args(rb_mEDNT, EDNT_STR_INT_TO_BIGNUM, rb_s);
|
117
144
|
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
118
145
|
}
|
119
146
|
|
@@ -127,7 +154,7 @@ namespace edn
|
|
127
154
|
}
|
128
155
|
|
129
156
|
// value is outside of range of long type. Use ruby to convert it
|
130
|
-
prot_args args(EDNT_STR_DBL_TO_BIGNUM, edn_prot_rb_new_str(str));
|
157
|
+
prot_args args(rb_mEDNT, EDNT_STR_DBL_TO_BIGNUM, edn_prot_rb_new_str(str));
|
131
158
|
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
132
159
|
}
|
133
160
|
|
@@ -193,7 +220,7 @@ namespace edn
|
|
193
220
|
// get a set representation from the ruby side. See edn_turbo.rb
|
194
221
|
VALUE Parser::make_edn_symbol(VALUE sym)
|
195
222
|
{
|
196
|
-
prot_args args(
|
223
|
+
prot_args args(rb_mEDNT, EDNT_MAKE_EDN_SYMBOL, sym);
|
197
224
|
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
198
225
|
}
|
199
226
|
|
@@ -201,7 +228,7 @@ namespace edn
|
|
201
228
|
// get a set representation from the ruby side. See edn_turbo.rb
|
202
229
|
VALUE Parser::make_ruby_set(VALUE elems)
|
203
230
|
{
|
204
|
-
prot_args args(
|
231
|
+
prot_args args(rb_mEDNT, EDNT_MAKE_SET_METHOD, elems);
|
205
232
|
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
206
233
|
}
|
207
234
|
|
@@ -209,11 +236,38 @@ namespace edn
|
|
209
236
|
// get an object representation from the ruby side using the given symbol name
|
210
237
|
VALUE Parser::tagged_element(VALUE name, VALUE data)
|
211
238
|
{
|
212
|
-
prot_args args(
|
239
|
+
prot_args args(rb_mEDNT, EDNT_TAGGED_ELEM, name, data);
|
213
240
|
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
214
241
|
}
|
215
242
|
|
216
243
|
|
244
|
+
// =================================================================
|
245
|
+
// METADATA
|
246
|
+
//
|
247
|
+
// returns an array of metadata value(s) saved in reverse order
|
248
|
+
// (right to left) - the ruby side will interpret this
|
249
|
+
VALUE Parser::ruby_meta()
|
250
|
+
{
|
251
|
+
VALUE m = rb_ary_new();
|
252
|
+
|
253
|
+
while (!metadata.empty()) {
|
254
|
+
rb_ary_push(m, metadata.back());
|
255
|
+
metadata.pop_back();
|
256
|
+
}
|
257
|
+
|
258
|
+
return m;
|
259
|
+
}
|
260
|
+
|
261
|
+
//
|
262
|
+
// calls the ruby-side bind_meta to bind the metadata to the value
|
263
|
+
VALUE Parser::bind_meta_to_value(VALUE value)
|
264
|
+
{
|
265
|
+
prot_args args(rb_mEDNT, EDNT_BIND_META_TO_VALUE, value, ruby_meta());
|
266
|
+
return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
|
267
|
+
}
|
268
|
+
|
269
|
+
|
270
|
+
// =================================================================
|
217
271
|
//
|
218
272
|
// error reporting
|
219
273
|
void Parser::throw_error(int error)
|
data/ext/edn_turbo/main.cc
CHANGED
@@ -12,11 +12,15 @@ namespace edn {
|
|
12
12
|
VALUE rb_mEDNT;
|
13
13
|
|
14
14
|
// methods on the ruby side we'll call from here
|
15
|
-
VALUE EDNT_MAKE_EDN_SYMBOL
|
16
|
-
VALUE EDNT_MAKE_SET_METHOD
|
17
|
-
VALUE EDNT_TAGGED_ELEM
|
18
|
-
VALUE
|
19
|
-
VALUE
|
15
|
+
VALUE EDNT_MAKE_EDN_SYMBOL = Qnil;
|
16
|
+
VALUE EDNT_MAKE_SET_METHOD = Qnil;
|
17
|
+
VALUE EDNT_TAGGED_ELEM = Qnil;
|
18
|
+
VALUE EDNT_BIND_META_TO_VALUE = Qnil;
|
19
|
+
VALUE EDNT_STR_INT_TO_BIGNUM = Qnil;
|
20
|
+
VALUE EDNT_STR_DBL_TO_BIGNUM = Qnil;
|
21
|
+
|
22
|
+
// returned when EOF - defined as a constant in EDN module
|
23
|
+
VALUE EDNT_EOF = Qnil;
|
20
24
|
|
21
25
|
//
|
22
26
|
// wrappers to hook the class w/ the C-api
|
@@ -82,7 +86,9 @@ namespace edn {
|
|
82
86
|
static VALUE read(VALUE self, VALUE data)
|
83
87
|
{
|
84
88
|
const char* stream = StringValueCStr(data);
|
85
|
-
|
89
|
+
if (stream)
|
90
|
+
return get_parser(self)->parse(stream, std::strlen(stream) );
|
91
|
+
return Qnil;
|
86
92
|
}
|
87
93
|
|
88
94
|
//
|
@@ -130,11 +136,15 @@ void Init_edn_turbo(void)
|
|
130
136
|
rb_define_method(rb_cParser, "ext_next", (VALUE(*)(ANYARGS)) &edn::next, 0 );
|
131
137
|
|
132
138
|
// bind ruby methods we'll call - these should be defined in edn_turbo.rb
|
133
|
-
edn::EDNT_MAKE_EDN_SYMBOL
|
134
|
-
edn::EDNT_MAKE_SET_METHOD
|
135
|
-
edn::EDNT_TAGGED_ELEM
|
136
|
-
edn::
|
137
|
-
edn::
|
139
|
+
edn::EDNT_MAKE_EDN_SYMBOL = rb_intern("make_edn_symbol");
|
140
|
+
edn::EDNT_MAKE_SET_METHOD = rb_intern("make_set");
|
141
|
+
edn::EDNT_TAGGED_ELEM = rb_intern("tagged_element");
|
142
|
+
edn::EDNT_BIND_META_TO_VALUE = rb_intern("bind_metadata_to_value");
|
143
|
+
edn::EDNT_STR_INT_TO_BIGNUM = rb_intern("string_int_to_bignum");
|
144
|
+
edn::EDNT_STR_DBL_TO_BIGNUM = rb_intern("string_double_to_bignum");
|
145
|
+
|
146
|
+
// so we can return EOF directly
|
147
|
+
edn::EDNT_EOF = rb_const_get(edn::rb_mEDNT, rb_intern("EOF"));
|
138
148
|
|
139
149
|
// import whatever else we've defined in the ruby side
|
140
150
|
rb_require("edn_turbo/edn_parser");
|
data/lib/edn_turbo/edn_parser.rb
CHANGED
data/lib/edn_turbo/version.rb
CHANGED
data/lib/edn_turbo.rb
CHANGED
@@ -91,4 +91,34 @@ module EDNT
|
|
91
91
|
str.to_f
|
92
92
|
end
|
93
93
|
|
94
|
+
# ============================================================================
|
95
|
+
# emulate EDN::Metadata
|
96
|
+
module Metadata
|
97
|
+
attr_accessor :metadata
|
98
|
+
end
|
99
|
+
|
100
|
+
# ----------------------------------------------------------------------------
|
101
|
+
# bind the given meta to the value
|
102
|
+
#
|
103
|
+
def self.bind_metadata_to_value(value, ext_meta)
|
104
|
+
|
105
|
+
meta = ext_meta
|
106
|
+
|
107
|
+
metadata = meta.reduce({}) do |acc, m|
|
108
|
+
case m
|
109
|
+
when Symbol then acc.merge(m => true)
|
110
|
+
when EDN::Type::Symbol then acc.merge(:tag => m)
|
111
|
+
else acc.merge(m)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if !metadata.empty?
|
116
|
+
value.extend Metadata
|
117
|
+
value.metadata = metadata
|
118
|
+
end
|
119
|
+
|
120
|
+
value
|
121
|
+
end
|
122
|
+
|
123
|
+
|
94
124
|
end # EDN namespace
|
data/test/test_output_diff.rb
CHANGED
@@ -84,6 +84,18 @@ class EDNT_Test < Minitest::Test
|
|
84
84
|
|
85
85
|
end
|
86
86
|
|
87
|
+
def test_symbol
|
88
|
+
|
89
|
+
check_file('test/symbol.edn',
|
90
|
+
[
|
91
|
+
EDN::Type::Symbol.new("asymbol"),
|
92
|
+
EDN::Type::Symbol.new("with'_a_'"),
|
93
|
+
EDN::Type::Symbol.new("with.123"),
|
94
|
+
]
|
95
|
+
)
|
96
|
+
|
97
|
+
end
|
98
|
+
|
87
99
|
def test_unicode
|
88
100
|
|
89
101
|
check_file('test/unicode.edn',
|
@@ -129,6 +141,17 @@ class EDNT_Test < Minitest::Test
|
|
129
141
|
)
|
130
142
|
end
|
131
143
|
|
144
|
+
|
145
|
+
def test_metadata
|
146
|
+
f = EDNT::read(File.open('test/metadata.edn').read)
|
147
|
+
assert_equal([98.6, 99.7], f)
|
148
|
+
assert_equal({:doc=>"This is my vector", :rel=>:temps}, f.metadata)
|
149
|
+
|
150
|
+
f = EDNT::read(File.open('test/metadata2.edn').read)
|
151
|
+
assert_equal([1, 2], f)
|
152
|
+
assert_equal({:foo=>true, :tag=>EDN::Type::Symbol.new('String'), :bar=>2}, f.metadata)
|
153
|
+
end
|
154
|
+
|
132
155
|
#
|
133
156
|
# for testing tagged element #edn_turbo/test_tagged
|
134
157
|
class Tagged
|
@@ -151,7 +174,7 @@ class EDNT_Test < Minitest::Test
|
|
151
174
|
assert_equal([345, :a], @parser.parse('#edn_turbo/test_tagged { :item 345 :other :a }'))
|
152
175
|
end
|
153
176
|
|
154
|
-
def
|
177
|
+
def test_operators
|
155
178
|
|
156
179
|
check_file('test/operators.edn',
|
157
180
|
[EDN::Type::Symbol.new('/'),
|
@@ -168,6 +191,10 @@ class EDNT_Test < Minitest::Test
|
|
168
191
|
EDN::Type::Symbol.new('='),
|
169
192
|
EDN::Type::Symbol.new('-'),
|
170
193
|
EDN::Type::Symbol.new('+'),
|
194
|
+
# [1, EDN::Type::Symbol.new('/'), 2],
|
195
|
+
# [3, EDN::Type::Symbol.new('/'), 4],
|
196
|
+
[5, EDN::Type::Symbol.new('/'), 6],
|
197
|
+
[7, EDN::Type::Symbol.new('/'), 8]
|
171
198
|
]
|
172
199
|
)
|
173
200
|
|