edn_turbo 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|