From fbc1a893ffbab369bb14166c5c1bdc67662d4cd2 Mon Sep 17 00:00:00 2001 From: Isha Date: Mon, 3 Mar 2014 03:59:00 +0000 Subject: [PATCH] C extensin for Variable#lax_parse --- ext/liquid/liquid_ext.c | 1 + ext/liquid/liquid_ext.h | 1 + ext/liquid/variable.c | 179 +++++++++++++++++++++++++++++++++++ ext/liquid/variable.h | 13 +++ lib/liquid/variable.rb | 33 ++++--- test/liquid/variable_test.rb | 4 +- 6 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 ext/liquid/variable.c create mode 100644 ext/liquid/variable.h diff --git a/ext/liquid/liquid_ext.c b/ext/liquid/liquid_ext.c index d611231..2df9e19 100644 --- a/ext/liquid/liquid_ext.c +++ b/ext/liquid/liquid_ext.c @@ -12,4 +12,5 @@ void Init_liquid(void) init_liquid_tokenizer(); init_liquid_block(); + init_liquid_variable(); } diff --git a/ext/liquid/liquid_ext.h b/ext/liquid/liquid_ext.h index 3eba3ae..1ea396b 100644 --- a/ext/liquid/liquid_ext.h +++ b/ext/liquid/liquid_ext.h @@ -8,6 +8,7 @@ #include "tokenizer.h" #include "block.h" #include "utils.h" +#include "variable.h" extern VALUE mLiquid; extern VALUE cLiquidTemplate, cLiquidTag, cLiquidVariable; diff --git a/ext/liquid/variable.c b/ext/liquid/variable.c new file mode 100644 index 0000000..669edfe --- /dev/null +++ b/ext/liquid/variable.c @@ -0,0 +1,179 @@ +#include "liquid_ext.h" + +VALUE cLiquidVariable; +extern VALUE mLiquid; + +static void free_variable(void *ptr) +{ + struct liquid_variable *variable = ptr; + xfree(variable); +} + +static VALUE rb_variable_allocate(VALUE klass) +{ + VALUE obj; + struct liquid_variable *variable; + + obj = Data_Make_Struct(klass, struct liquid_variable, NULL, free_variable, variable); + return obj; +} + +static inline int skip_whitespace(char * str, int len) +{ + int skipped = 0; char * ptr = str; + while (skipped < len && isspace(*ptr)) + {skipped++; ptr++;} + return skipped; +} + +static char * get_quoted_fragment(char * str, int len, int * ret_size, int * end_offset, bool colon) +{ + int p = 0; /* Current position in string */ + int start = -1, end = -1; /* Start and end indices for the found string */ + char quoted_by = -1; /* Is the current part of string quoted by a single or double quote? If so + ignore any special chars */ + + while (p < len) { + + switch (str[p]) { + case '"': + if (start == -1) {start = p; quoted_by = '"';} + else if (str[start] == '"') {end = p; goto quoted_fragment_found;} + else if (quoted_by == -1) quoted_by = '"'; + else if (quoted_by == '"') quoted_by = -1; + break; + case '\'': + if (start == -1) {start = p; quoted_by = '\'';} + else if (str[start] == '\'') {end = p; goto quoted_fragment_found;} + else if (quoted_by == -1) quoted_by = '\''; + else if (quoted_by == '\'') quoted_by = -1; + break; + case ':': + if (colon) + if (start != -1 && quoted_by == -1) {end = p-1; goto quoted_fragment_found;} + else + if (start == -1) start = p; + break; + case '|': + case ',': + case '\n': + case '\r': + case '\f': + case '\t': + case '\v': + case ' ': + if (start != -1 && quoted_by == -1) {end = p-1; goto quoted_fragment_found;} + break; + default: + if (start == -1) start = p; + break; + } + p++; + } + if (p == len && start != -1 && end == -1) end = len-1; + +quoted_fragment_found: + if (end >= start) { + *ret_size = end-start+1; + *end_offset = end+1; + return &str[start]; + } else { + *ret_size = 0; + return NULL; + } +} + +static VALUE get_filters(char * str, int len, VALUE self) { + VALUE filters_arr = rb_ary_new(); + + int p = 0; + int ret_size, end_offset; + char * f; + + while(p + +struct liquid_variable { + char *markup; long markup_len; + char *name; long name_len; +}; + +void init_liquid_variable(); + +#endif diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index c661d97..60d9e51 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -11,7 +11,6 @@ module Liquid # {{ user | link }} # class Variable - FilterParser = /(?:#{FilterSeparator}|(?:\s*(?:#{QuotedFragment}|#{ArgumentSeparator})\s*)+)/o EasyParse = /\A *(\w+(?:\.\w+)*) *\z/ attr_accessor :filters, :name, :warnings @@ -35,22 +34,22 @@ module Liquid end end - def lax_parse(markup) - @filters = [] - if match = markup.match(/\s*(#{QuotedFragment})(.*)/o) - @name = match[1] - if match[2].match(/#{FilterSeparator}\s*(.*)/o) - filters = Regexp.last_match(1).scan(FilterParser) - filters.each do |f| - if matches = f.match(/\s*(\w+)/) - filtername = matches[1] - filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten - @filters << [filtername, filterargs] - end - end - end - end - end +# def lax_parse(markup) +# @filters = [] +# if match = markup.match(/\s*(#{QuotedFragment})(.*)/o) +# @name = match[1] +# if match[2].match(/#{FilterSeparator}\s*(.*)/o) +# filters = Regexp.last_match(1).scan(FilterParser) +# filters.each do |f| +# if matches = f.match(/\s*(\w+)/) +# filtername = matches[1] +# filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten +# @filters << [filtername, filterargs] +# end +# end +# end +# end +# end def strict_parse(markup) # Very simple valid cases diff --git a/test/liquid/variable_test.rb b/test/liquid/variable_test.rb index 30513c3..284e981 100644 --- a/test/liquid/variable_test.rb +++ b/test/liquid/variable_test.rb @@ -51,11 +51,9 @@ class VariableTest < Test::Unit::TestCase end def test_filter_with_date_parameter - var = Variable.new(%! '2006-06-06' | date: "%m/%d/%Y"!) assert_equal "'2006-06-06'", var.name assert_equal [["date",["\"%m/%d/%Y\""]]], var.filters - end def test_filters_without_whitespace @@ -73,7 +71,7 @@ class VariableTest < Test::Unit::TestCase end def test_symbol - var = Variable.new("http://disney.com/logo.gif | image: 'med' ", :error_mode => :lax) + var = Variable.new("http://disney.com/logo.gif | image: 'med'", :error_mode => :lax) assert_equal "http://disney.com/logo.gif", var.name assert_equal [["image",["'med'"]]], var.filters end