Strict variable parsing

This is the first iteration of the strict C lexer and variable parser. Currently, there is a tight coupling between a few of the methods and Ruby, but this is expected to go away in the future.

Feel free to start reviewing, though this is heavily a WIP and we'll continue making changes tomorrow.

```
/Users/jli/.rbenv/versions/2.1.0/bin/ruby ./performance.rb bare benchmark lax

Running benchmark for 20 seconds (with 5 seconds warmup).

Calculating -------------------------------------
              parse:         4 i/100ms
-------------------------------------------------
              parse:       46.0 (±4.3%) i/s -        920 in  20.045934s
/Users/jli/.rbenv/versions/2.1.0/bin/ruby ./performance.rb c benchmark lax

Running benchmark for 20 seconds (with 5 seconds warmup).

Calculating -------------------------------------
              parse:         7 i/100ms
-------------------------------------------------
              parse:       78.7 (±2.5%) i/s -       1575 in  20.036520s
```

~40% less time spent in parsing, and is very reproducible.

Paired with @xthexder 

@Shopify/webscale @Shopify/liquid
I agree with the readability issue though. Wrap it in a macro perhaps

-- Tobi
CEO Shopify

(mobile)

> On Oct 16, 2014, at 6:42 PM, Dylan Thacker-Smith <notifications@github.com> wrote:
> 
> In ext/liquid_c/lexer.c:
> 
> > +    switch (c) {
> > +        case '|': case '.': case ':': case ',':
> > +        case '[': case ']': case '(': case ')':
> > +            return 1;
> > +    }
> > +    return 0;
> > +}
> > +
> > +inline static const char *skip_white(const char *cur, const char *end) {
> > +    while (cur < end && is_white(*cur)) ++cur;
> > +    return cur;
> > +}
> > +
> > +// Returns a pointer to the character after the end of the match.
> > +inline static const char *matches(const char *cur, const char *end, const char *pattern) {
> > +    while (cur < end && *pattern != '\0') {
> If the function is inline and a string literal is passed in as the pattern, then strlen(pattern) gets computed at compile time with -O2 (e.g. you will see mov $0x8,%edx in the assembly for "contains")`.
> 
> I would also be surprised if your character-wise comparison was faster than memcmp which I would suspect would do a 64-bit comparison of the whole "contains" string. I did a micro-benchmark of 1000000000 iterations of your character comparison match against a contains string that was passed through the program args (wanted to make sure it wasn't optimized out) and it took 11.696s, compared to the memcmp version you have in the comment above which took 5.080s for the same number of iterations. It isn't worth rolling your own memcmp.
> 
> —
> Reply to this email directly or view it on GitHub.