summary refs log tree commit
path: root/ext/json
diff options
context:
space:
mode:
authorFlorian Frank <flori@ping.de>2010-10-05 11:00:09 +0200
committerFlorian Frank <flori@ping.de>2011-01-02 21:13:46 +0100
commit8714f0a88ccee67ea7ca1a9d5a40d9cf1c6dd5fb (patch)
tree9f1d194336debc54896944b80bbf3bbea44eb4dd /ext/json
parent02b20b1ec02513b7452e8585c6d45cbe565418d2 (diff)
downloadruby-json-8714f0a88ccee67ea7ca1a9d5a40d9cf1c6dd5fb.tar.gz
Added matching in pure/ext parser
Diffstat (limited to 'ext/json')
-rw-r--r--ext/json/ext/parser/parser.c103
-rw-r--r--ext/json/ext/parser/parser.h3
-rw-r--r--ext/json/ext/parser/parser.rl75
3 files changed, 135 insertions, 46 deletions
diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c
index a2f4601..43a1426 100644
--- a/ext/json/ext/parser/parser.c
+++ b/ext/json/ext/parser/parser.c
@@ -79,7 +79,7 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
 
 static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
           i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,
-          i_array_class, i_key_p, i_deep_const_get;
+          i_array_class, i_key_p, i_deep_const_get, i_match;
 
 
 #line 108 "parser.rl"
@@ -1361,21 +1361,34 @@ static const int JSON_string_en_main = 1;
 #line 471 "parser.rl"
 
 
+static int
+match_i(VALUE regexp, VALUE klass, VALUE memo)
+{
+    if (regexp == Qundef) return ST_STOP;
+    if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
+      RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
+        rb_ary_push(memo, klass);
+        return ST_STOP;
+    }
+    return ST_CONTINUE;
+}
+
 static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
 {
     int cs = EVIL;
+    VALUE match, memo;
 
     *result = rb_str_buf_new(0);
     
-#line 1371 "parser.c"
+#line 1384 "parser.c"
         {
         cs = JSON_string_start;
         }
 
-#line 479 "parser.rl"
+#line 492 "parser.rl"
     json->memo = p;
     
-#line 1379 "parser.c"
+#line 1392 "parser.c"
         {
         if ( p == pe )
                 goto _test_eof;
@@ -1404,13 +1417,13 @@ tr2:
         {
         *result = json_string_unescape(*result, json->memo + 1, p);
         if (NIL_P(*result)) {
-                        p--;
-                        {p++; cs = 8; goto _out;}
-                } else {
-                        FORCE_UTF8(*result);
-                        {p = (( p + 1))-1;}
-                }
-        }
+            p--;
+            {p++; cs = 8; goto _out;}
+        } else {
+            FORCE_UTF8(*result);
+            {p = (( p + 1))-1;}
+        }
+    }
 #line 468 "parser.rl"
         { p--; {p++; cs = 8; goto _out;} }
         goto st8;
@@ -1418,7 +1431,7 @@ st8:
         if ( ++p == pe )
                 goto _test_eof8;
 case 8:
-#line 1422 "parser.c"
+#line 1435 "parser.c"
         goto st0;
 st3:
         if ( ++p == pe )
@@ -1494,7 +1507,21 @@ case 7:
         _out: {}
         }
 
-#line 481 "parser.rl"
+#line 494 "parser.rl"
+
+        if (json->create_additions) {
+                match = json->match;
+                memo = rb_ary_new2(2);
+                rb_ary_push(memo, *result);
+                if (RTEST(match)) {
+                        VALUE klass;
+                        rb_hash_foreach(match, match_i, memo);
+                        klass = rb_ary_entry(memo, 1);
+                        if (RTEST(klass)) {
+                                *result = rb_funcall(klass, i_json_create, 1, *result);
+                        }
+                }
+        }
 
     if (json->symbolize_names && json->parsing_name) {
       *result = rb_str_intern(*result);
@@ -1508,7 +1535,7 @@ case 7:
 
 
 
-#line 1512 "parser.c"
+#line 1539 "parser.c"
 static const int JSON_start = 1;
 static const int JSON_first_final = 10;
 static const int JSON_error = 0;
@@ -1516,7 +1543,7 @@ static const int JSON_error = 0;
 static const int JSON_en_main = 1;
 
 
-#line 518 "parser.rl"
+#line 545 "parser.rl"
 
 
 /*
@@ -1649,14 +1676,17 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
             tmp = ID2SYM(i_create_additions);
             if (option_given_p(opts, tmp)) {
                 VALUE create_additions = rb_hash_aref(opts, tmp);
-                if (RTEST(create_additions)) {
-                    json->create_id = rb_funcall(mJSON, i_create_id, 0);
-                } else {
-                    json->create_id = Qnil;
-                }
-            } else {
-                json->create_id = rb_funcall(mJSON, i_create_id, 0);
-            }
+                                json->create_additions = RTEST(create_additions);
+                        } else {
+                                json->create_additions = 1;
+                        }
+            tmp = ID2SYM(i_create_id);
+            if (option_given_p(opts, tmp)) {
+                VALUE create_id = rb_hash_aref(opts, tmp);
+                                json->create_id = create_id;
+                        } else {
+                                json->create_id = rb_funcall(mJSON, i_create_id, 0);
+                        }
             tmp = ID2SYM(i_object_class);
             if (option_given_p(opts, tmp)) {
                 json->object_class = rb_hash_aref(opts, tmp);
@@ -1669,6 +1699,17 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
             } else {
                 json->array_class = Qnil;
             }
+            tmp = ID2SYM(i_match);
+            if (option_given_p(opts, tmp)) {
+                VALUE match = rb_hash_aref(opts, tmp);
+                if (RTEST(match)) {
+                    json->match = match;
+                } else {
+                    json->match = Qnil;
+                }
+            } else {
+                json->match = Qnil;
+            }
         }
     } else {
         json->max_nesting = 19;
@@ -1698,16 +1739,16 @@ static VALUE cParser_parse(VALUE self)
     GET_PARSER;
 
     
-#line 1702 "parser.c"
+#line 1743 "parser.c"
         {
         cs = JSON_start;
         }
 
-#line 699 "parser.rl"
+#line 740 "parser.rl"
     p = json->source;
     pe = p + json->len;
     
-#line 1711 "parser.c"
+#line 1752 "parser.c"
         {
         if ( p == pe )
                 goto _test_eof;
@@ -1763,7 +1804,7 @@ case 5:
                 goto st1;
         goto st5;
 tr3:
-#line 507 "parser.rl"
+#line 534 "parser.rl"
         {
         char *np;
         json->current_nesting = 1;
@@ -1772,7 +1813,7 @@ tr3:
     }
         goto st10;
 tr4:
-#line 500 "parser.rl"
+#line 527 "parser.rl"
         {
         char *np;
         json->current_nesting = 1;
@@ -1784,7 +1825,7 @@ st10:
         if ( ++p == pe )
                 goto _test_eof10;
 case 10:
-#line 1788 "parser.c"
+#line 1829 "parser.c"
         switch( (*p) ) {
                 case 13: goto st10;
                 case 32: goto st10;
@@ -1841,7 +1882,7 @@ case 9:
         _out: {}
         }
 
-#line 702 "parser.rl"
+#line 743 "parser.rl"
 
     if (cs >= JSON_first_final && p == pe) {
         return result;
@@ -1864,6 +1905,7 @@ static void JSON_mark(JSON_Parser *json)
     rb_gc_mark_maybe(json->create_id);
     rb_gc_mark_maybe(json->object_class);
     rb_gc_mark_maybe(json->array_class);
+    rb_gc_mark_maybe(json->match);
 }
 
 static void JSON_free(JSON_Parser *json)
@@ -1916,6 +1958,7 @@ void Init_parser()
     i_symbolize_names = rb_intern("symbolize_names");
     i_object_class = rb_intern("object_class");
     i_array_class = rb_intern("array_class");
+    i_match = rb_intern("match");
     i_key_p = rb_intern("key?");
     i_deep_const_get = rb_intern("deep_const_get");
 #ifdef HAVE_RUBY_ENCODING_H
diff --git a/ext/json/ext/parser/parser.h b/ext/json/ext/parser/parser.h
index 688ffda..ab02b51 100644
--- a/ext/json/ext/parser/parser.h
+++ b/ext/json/ext/parser/parser.h
@@ -13,6 +13,7 @@
 #else
 #define FORCE_UTF8(obj)
 #endif
+#include "ruby/st.h"
 
 #define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key))
 
@@ -41,6 +42,8 @@ typedef struct JSON_ParserStruct {
     int symbolize_names;
     VALUE object_class;
     VALUE array_class;
+                int create_additions;
+                VALUE match;
 } JSON_Parser;
 
 #define GET_PARSER                          \
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl
index dd07485..f59038b 100644
--- a/ext/json/ext/parser/parser.rl
+++ b/ext/json/ext/parser/parser.rl
@@ -77,7 +77,7 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
 
 static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
           i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,
-          i_array_class, i_key_p, i_deep_const_get;
+          i_array_class, i_key_p, i_deep_const_get, i_match;
 
 %%{
     machine JSON_common;
@@ -457,28 +457,55 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
     action parse_string {
         *result = json_string_unescape(*result, json->memo + 1, p);
         if (NIL_P(*result)) {
-                        fhold;
-                        fbreak;
-                } else {
-                        FORCE_UTF8(*result);
-                        fexec p + 1;
-                }
-        }
+            fhold;
+            fbreak;
+        } else {
+            FORCE_UTF8(*result);
+            fexec p + 1;
+        }
+    }
 
     action exit { fhold; fbreak; }
 
     main := '"' ((^(["\\] | 0..0x1f) | '\\'["\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | '\\'^(["\\/bfnrtu]|0..0x1f))* %parse_string) '"' @exit;
 }%%
 
+static int
+match_i(VALUE regexp, VALUE klass, VALUE memo)
+{
+    if (regexp == Qundef) return ST_STOP;
+    if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
+      RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
+        rb_ary_push(memo, klass);
+        return ST_STOP;
+    }
+    return ST_CONTINUE;
+}
+
 static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
 {
     int cs = EVIL;
+    VALUE match, memo;
 
     *result = rb_str_buf_new(0);
     %% write init;
     json->memo = p;
     %% write exec;
 
+        if (json->create_additions) {
+                match = json->match;
+                memo = rb_ary_new2(2);
+                rb_ary_push(memo, *result);
+                if (RTEST(match)) {
+                        VALUE klass;
+                        rb_hash_foreach(match, match_i, memo);
+                        klass = rb_ary_entry(memo, 1);
+                        if (RTEST(klass)) {
+                                *result = rb_funcall(klass, i_json_create, 1, *result);
+                        }
+                }
+        }
+
     if (json->symbolize_names && json->parsing_name) {
       *result = rb_str_intern(*result);
     }
@@ -647,14 +674,17 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
             tmp = ID2SYM(i_create_additions);
             if (option_given_p(opts, tmp)) {
                 VALUE create_additions = rb_hash_aref(opts, tmp);
-                if (RTEST(create_additions)) {
-                    json->create_id = rb_funcall(mJSON, i_create_id, 0);
-                } else {
-                    json->create_id = Qnil;
-                }
-            } else {
-                json->create_id = rb_funcall(mJSON, i_create_id, 0);
-            }
+                                json->create_additions = RTEST(create_additions);
+                        } else {
+                                json->create_additions = 1;
+                        }
+            tmp = ID2SYM(i_create_id);
+            if (option_given_p(opts, tmp)) {
+                VALUE create_id = rb_hash_aref(opts, tmp);
+                                json->create_id = create_id;
+                        } else {
+                                json->create_id = rb_funcall(mJSON, i_create_id, 0);
+                        }
             tmp = ID2SYM(i_object_class);
             if (option_given_p(opts, tmp)) {
                 json->object_class = rb_hash_aref(opts, tmp);
@@ -667,6 +697,17 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
             } else {
                 json->array_class = Qnil;
             }
+            tmp = ID2SYM(i_match);
+            if (option_given_p(opts, tmp)) {
+                VALUE match = rb_hash_aref(opts, tmp);
+                if (RTEST(match)) {
+                    json->match = match;
+                } else {
+                    json->match = Qnil;
+                }
+            } else {
+                json->match = Qnil;
+            }
         }
     } else {
         json->max_nesting = 19;
@@ -721,6 +762,7 @@ static void JSON_mark(JSON_Parser *json)
     rb_gc_mark_maybe(json->create_id);
     rb_gc_mark_maybe(json->object_class);
     rb_gc_mark_maybe(json->array_class);
+    rb_gc_mark_maybe(json->match);
 }
 
 static void JSON_free(JSON_Parser *json)
@@ -773,6 +815,7 @@ void Init_parser()
     i_symbolize_names = rb_intern("symbolize_names");
     i_object_class = rb_intern("object_class");
     i_array_class = rb_intern("array_class");
+    i_match = rb_intern("match");
     i_key_p = rb_intern("key?");
     i_deep_const_get = rb_intern("deep_const_get");
 #ifdef HAVE_RUBY_ENCODING_H