class Gherkin::CLexer::El

Public Class Methods

new(p1) click to toggle source
static VALUE CLexer_init(VALUE self, VALUE listener)
{
  lexer_state *lxr; 
  rb_iv_set(self, "@listener", listener);
  
  lxr = NULL;
  DATA_GET(self, lexer_state, lxr);
  lexer_init(lxr);
  
  return self;
}

Public Instance Methods

scan(p1) click to toggle source
static VALUE CLexer_scan(VALUE self, VALUE input)
{
  VALUE input_copy;
  char *data;
  size_t len;
  VALUE listener = rb_iv_get(self, "@listener");

  lexer_state *lexer;
  lexer = NULL;
  DATA_GET(self, lexer_state, lexer);

  input_copy = rb_str_dup(input);

  rb_str_append(input_copy, rb_str_new2("\n%_FEATURE_END_%"));
  data = RSTRING_PTR(input_copy);
  len = RSTRING_LEN(input_copy);
  
  if (len == 0) { 
    rb_raise(rb_eGherkinLexingError, "No content to lex.");
  } else {

    const char *p, *pe, *eof;
    int cs = 0;
    
    VALUE current_row = Qnil;

    p = data;
    pe = data + len;
    eof = pe;
    
    assert(*pe == '\0' && "pointer does not end on NULL");
    
    
#line 1523 "ext/gherkin_lexer_el/gherkin_lexer_el.c"
        {
        cs = lexer_start;
        }

#line 425 "ragel/i18n/el.c.rl"
    
#line 1530 "ext/gherkin_lexer_el/gherkin_lexer_el.c"
        {
        int _klen;
        unsigned int _trans;
        const char *_acts;
        unsigned int _nacts;
        const char *_keys;

        if ( p == pe )
                goto _test_eof;
        if ( cs == 0 )
                goto _out;
_resume:
        _keys = _lexer_trans_keys + _lexer_key_offsets[cs];
        _trans = _lexer_index_offsets[cs];

        _klen = _lexer_single_lengths[cs];
        if ( _klen > 0 ) {
                const char *_lower = _keys;
                const char *_mid;
                const char *_upper = _keys + _klen - 1;
                while (1) {
                        if ( _upper < _lower )
                                break;

                        _mid = _lower + ((_upper-_lower) >> 1);
                        if ( (*p) < *_mid )
                                _upper = _mid - 1;
                        else if ( (*p) > *_mid )
                                _lower = _mid + 1;
                        else {
                                _trans += (unsigned int)(_mid - _keys);
                                goto _match;
                        }
                }
                _keys += _klen;
                _trans += _klen;
        }

        _klen = _lexer_range_lengths[cs];
        if ( _klen > 0 ) {
                const char *_lower = _keys;
                const char *_mid;
                const char *_upper = _keys + (_klen<<1) - 2;
                while (1) {
                        if ( _upper < _lower )
                                break;

                        _mid = _lower + (((_upper-_lower) >> 1) & ~1);
                        if ( (*p) < _mid[0] )
                                _upper = _mid - 2;
                        else if ( (*p) > _mid[1] )
                                _lower = _mid + 2;
                        else {
                                _trans += (unsigned int)((_mid - _keys)>>1);
                                goto _match;
                        }
                }
                _trans += _klen;
        }

_match:
        cs = _lexer_trans_targs[_trans];

        if ( _lexer_trans_actions[_trans] == 0 )
                goto _again;

        _acts = _lexer_actions + _lexer_trans_actions[_trans];
        _nacts = (unsigned int) *_acts++;
        while ( _nacts-- > 0 )
        {
                switch ( *_acts++ )
                {
        case 0:
#line 83 "ragel/i18n/el.c.rl"
        {
                MARK(content_start, p);
    lexer->current_line = lexer->line_number;
    lexer->start_col = lexer->content_start - lexer->last_newline - (lexer->keyword_end - lexer->keyword_start) + 2;
  }
        break;
        case 1:
#line 89 "ragel/i18n/el.c.rl"
        {
    MARK(content_start, p);
  }
        break;
        case 2:
#line 93 "ragel/i18n/el.c.rl"
        {
    lexer->current_line = lexer->line_number;
    lexer->start_col = p - data - lexer->last_newline;
  }
        break;
        case 3:
#line 98 "ragel/i18n/el.c.rl"
        {
    int len = LEN(content_start, PTR_TO(final_newline));
    int type_len = LEN(docstring_content_type_start, PTR_TO(docstring_content_type_end));

    if (len < 0) len = 0;
    if (type_len < 0) len = 0;

    store_docstring_content(listener, lexer->start_col, PTR_TO(docstring_content_type_start), type_len, PTR_TO(content_start), len, lexer->current_line);
  }
        break;
        case 4:
#line 108 "ragel/i18n/el.c.rl"
        { 
    MARK(docstring_content_type_start, p);
  }
        break;
        case 5:
#line 112 "ragel/i18n/el.c.rl"
        { 
    MARK(docstring_content_type_end, p);
  }
        break;
        case 6:
#line 116 "ragel/i18n/el.c.rl"
        {
    STORE_KW_END_CON(feature);
  }
        break;
        case 7:
#line 120 "ragel/i18n/el.c.rl"
        {
    STORE_KW_END_CON(background);
  }
        break;
        case 8:
#line 124 "ragel/i18n/el.c.rl"
        {
    STORE_KW_END_CON(scenario);
  }
        break;
        case 9:
#line 128 "ragel/i18n/el.c.rl"
        {
    STORE_KW_END_CON(scenario_outline);
  }
        break;
        case 10:
#line 132 "ragel/i18n/el.c.rl"
        {
    STORE_KW_END_CON(examples);
  }
        break;
        case 11:
#line 136 "ragel/i18n/el.c.rl"
        {
    store_kw_con(listener, "step",
      PTR_TO(keyword_start), LEN(keyword_start, PTR_TO(keyword_end)),
      PTR_TO(content_start), LEN(content_start, p), 
      lexer->current_line);
  }
        break;
        case 12:
#line 143 "ragel/i18n/el.c.rl"
        {
    STORE_ATTR(comment);
    lexer->mark = 0;
  }
        break;
        case 13:
#line 148 "ragel/i18n/el.c.rl"
        {
    STORE_ATTR(tag);
    lexer->mark = 0;
  }
        break;
        case 14:
#line 153 "ragel/i18n/el.c.rl"
        {
    lexer->line_number += 1;
    MARK(final_newline, p);
  }
        break;
        case 15:
#line 158 "ragel/i18n/el.c.rl"
        {
    MARK(last_newline, p + 1);
  }
        break;
        case 16:
#line 162 "ragel/i18n/el.c.rl"
        {
    if (lexer->mark == 0) {
      MARK(mark, p);
    }
  }
        break;
        case 17:
#line 168 "ragel/i18n/el.c.rl"
        {
    MARK(keyword_end, p);
    MARK(keyword_start, PTR_TO(mark));
    MARK(content_start, p + 1);
    lexer->mark = 0;
  }
        break;
        case 18:
#line 175 "ragel/i18n/el.c.rl"
        {
    MARK(content_end, p);
  }
        break;
        case 19:
#line 179 "ragel/i18n/el.c.rl"
        {
    p = p - 1;
    lexer->current_line = lexer->line_number;
    current_row = rb_ary_new();
  }
        break;
        case 20:
#line 185 "ragel/i18n/el.c.rl"
        {
                MARK(content_start, p);
  }
        break;
        case 21:
#line 189 "ragel/i18n/el.c.rl"
        {
    VALUE re_pipe, re_newline, re_backslash;
    VALUE con = ENCODED_STR_NEW(PTR_TO(content_start), LEN(content_start, p));
    rb_funcall(con, rb_intern("strip!"), 0);
    re_pipe      = rb_reg_regcomp(rb_str_new2("\\\\\\|"));
    re_newline   = rb_reg_regcomp(rb_str_new2("\\\\n"));
    re_backslash = rb_reg_regcomp(rb_str_new2("\\\\\\\\"));
    rb_funcall(con, rb_intern("gsub!"), 2, re_pipe,      rb_str_new2("|"));
    rb_funcall(con, rb_intern("gsub!"), 2, re_newline,   rb_str_new2("\n"));
    rb_funcall(con, rb_intern("gsub!"), 2, re_backslash, rb_str_new2("\\"));

    rb_ary_push(current_row, con);
  }
        break;
        case 22:
#line 203 "ragel/i18n/el.c.rl"
        {
    rb_funcall(listener, rb_intern("row"), 2, current_row, INT2FIX(lexer->current_line));
  }
        break;
        case 23:
#line 207 "ragel/i18n/el.c.rl"
        {
    int line;
    if (cs < lexer_first_final) {
      size_t count = 0;
      VALUE newstr_val;
      char *newstr;
      int newstr_count = 0;        
      size_t len;
      const char *buff;
      if (lexer->last_newline != 0) {
        len = LEN(last_newline, eof);
        buff = PTR_TO(last_newline);
      } else {
        len = strlen(data);
        buff = data;
      }

      /* Allocate as a ruby string so that it gets cleaned up by GC */
      newstr_val = rb_str_new(buff, len);
      newstr = RSTRING_PTR(newstr_val);


      for (count = 0; count < len; count++) {
        if(buff[count] == 10) {
          newstr[newstr_count] = '\0'; /* terminate new string at first newline found */
          break;
        } else {
          if (buff[count] == '%') {
            newstr[newstr_count++] = buff[count];
            newstr[newstr_count] = buff[count];
          } else {
            newstr[newstr_count] = buff[count];
          }
        }
        newstr_count++;
      }

      line = lexer->line_number;
      lexer_init(lexer); /* Re-initialize so we can scan again with the same lexer */
      raise_lexer_error(newstr, line);
    } else {
      rb_funcall(listener, rb_intern("eof"), 0);
    }
  }
        break;
#line 1820 "ext/gherkin_lexer_el/gherkin_lexer_el.c"
                }
        }

_again:
        if ( cs == 0 )
                goto _out;
        if ( ++p != pe )
                goto _resume;
        _test_eof: {}
        if ( p == eof )
        {
        const char *__acts = _lexer_actions + _lexer_eof_actions[cs];
        unsigned int __nacts = (unsigned int) *__acts++;
        while ( __nacts-- > 0 ) {
                switch ( *__acts++ ) {
        case 23:
#line 207 "ragel/i18n/el.c.rl"
        {
    int line;
    if (cs < lexer_first_final) {
      size_t count = 0;
      VALUE newstr_val;
      char *newstr;
      int newstr_count = 0;        
      size_t len;
      const char *buff;
      if (lexer->last_newline != 0) {
        len = LEN(last_newline, eof);
        buff = PTR_TO(last_newline);
      } else {
        len = strlen(data);
        buff = data;
      }

      /* Allocate as a ruby string so that it gets cleaned up by GC */
      newstr_val = rb_str_new(buff, len);
      newstr = RSTRING_PTR(newstr_val);


      for (count = 0; count < len; count++) {
        if(buff[count] == 10) {
          newstr[newstr_count] = '\0'; /* terminate new string at first newline found */
          break;
        } else {
          if (buff[count] == '%') {
            newstr[newstr_count++] = buff[count];
            newstr[newstr_count] = buff[count];
          } else {
            newstr[newstr_count] = buff[count];
          }
        }
        newstr_count++;
      }

      line = lexer->line_number;
      lexer_init(lexer); /* Re-initialize so we can scan again with the same lexer */
      raise_lexer_error(newstr, line);
    } else {
      rb_funcall(listener, rb_intern("eof"), 0);
    }
  }
        break;
#line 1883 "ext/gherkin_lexer_el/gherkin_lexer_el.c"
                }
        }
        }

        _out: {}
        }

#line 426 "ragel/i18n/el.c.rl"

    assert(p <= pe && "data overflow after parsing execute");
    assert(lexer->content_start <= len && "content starts after data end");
    assert(lexer->mark < len && "mark is after data end");
    
    /* Reset lexer by re-initializing the whole thing */
    lexer_init(lexer);

    if (cs == lexer_error) {
      rb_raise(rb_eGherkinLexingError, "Invalid format, lexing fails.");
    } else {
      return Qtrue;
    }
  }
}