/***********************************************************************/
/*                                                                     */
/*                           Objective Caml                            */
/*                                                                     */
/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
/*                                                                     */
/*  Copyright 1996 Institut National de Recherche en Informatique et   */
/*  en Automatique.  All rights reserved.  This file is distributed    */
/*  under the terms of the GNU Lesser General Public License, with     */
/*  the special exception on linking described in file ../LICENSE.     */
/*                                                                     */
/***********************************************************************/

/* $Id: lexing.c 6045 2004-01-01 16:42:43Z doligez $ */

/* The table-driven automaton for lexers generated by camllex. */

//Provides: caml_lex_array
//Requires: caml_jsbytes_of_string
function caml_lex_array(s) {
  s = caml_jsbytes_of_string(s);
  var l = s.length / 2;
  var a = new Array(l);
  for (var i = 0; i < l; i++)
    a[i] = ((s.charCodeAt(2 * i) | (s.charCodeAt(2 * i + 1) << 8)) << 16) >> 16;
  return a;
}

//Provides: caml_lex_engine
//Requires: caml_failwith, caml_lex_array
//Requires: caml_bytes_unsafe_get
function caml_lex_engine(tbl, start_state, lexbuf) {
  var lex_buffer = 2;
  var lex_buffer_len = 3;
  var lex_start_pos = 5;
  var lex_curr_pos = 6;
  var lex_last_pos = 7;
  var lex_last_action = 8;
  var lex_eof_reached = 9;
  var lex_base = 1;
  var lex_backtrk = 2;
  var lex_default = 3;
  var lex_trans = 4;
  var lex_check = 5;

  if (!tbl.lex_default) {
    tbl.lex_base = caml_lex_array(tbl[lex_base]);
    tbl.lex_backtrk = caml_lex_array(tbl[lex_backtrk]);
    tbl.lex_check = caml_lex_array(tbl[lex_check]);
    tbl.lex_trans = caml_lex_array(tbl[lex_trans]);
    tbl.lex_default = caml_lex_array(tbl[lex_default]);
  }

  var c,
    state = start_state;

  var buffer = lexbuf[lex_buffer];

  if (state >= 0) {
    /* First entry */
    lexbuf[lex_last_pos] = lexbuf[lex_start_pos] = lexbuf[lex_curr_pos];
    lexbuf[lex_last_action] = -1;
  } else {
    /* Reentry after refill */
    state = -state - 1;
  }
  for (;;) {
    /* Lookup base address or action number for current state */
    var base = tbl.lex_base[state];
    if (base < 0) return -base - 1;
    /* See if it's a backtrack point */
    var backtrk = tbl.lex_backtrk[state];
    if (backtrk >= 0) {
      lexbuf[lex_last_pos] = lexbuf[lex_curr_pos];
      lexbuf[lex_last_action] = backtrk;
    }
    /* See if we need a refill */
    if (lexbuf[lex_curr_pos] >= lexbuf[lex_buffer_len]) {
      if (lexbuf[lex_eof_reached] === 0) return -state - 1;
      else c = 256;
    } else {
      /* Read next input char */
      c = caml_bytes_unsafe_get(buffer, lexbuf[lex_curr_pos]);
      lexbuf[lex_curr_pos]++;
    }
    /* Determine next state */
    if (tbl.lex_check[base + c] === state) state = tbl.lex_trans[base + c];
    else state = tbl.lex_default[state];
    /* If no transition on this char, return to last backtrack point */
    if (state < 0) {
      lexbuf[lex_curr_pos] = lexbuf[lex_last_pos];
      if (lexbuf[lex_last_action] === -1) caml_failwith("lexing: empty token");
      else return lexbuf[lex_last_action];
    } else {
      /* Erase the EOF condition only if the EOF pseudo-character was
         consumed by the automaton (i.e. there was no backtrack above)
      */
      if (c === 256) lexbuf[lex_eof_reached] = 0;
    }
  }
}

/***********************************************/
/* New lexer engine, with memory of positions  */
/***********************************************/

//Provides: caml_new_lex_engine
//Requires: caml_failwith, caml_lex_array
//Requires: caml_jsbytes_of_string
//Requires: caml_bytes_unsafe_get
function caml_lex_run_mem(s, i, mem, curr_pos) {
  for (;;) {
    var dst = s.charCodeAt(i);
    i++;
    if (dst === 0xff) return;
    var src = s.charCodeAt(i);
    i++;
    if (src === 0xff) mem[dst + 1] = curr_pos;
    else mem[dst + 1] = mem[src + 1];
  }
}

function caml_lex_run_tag(s, i, mem) {
  for (;;) {
    var dst = s.charCodeAt(i);
    i++;
    if (dst === 0xff) return;
    var src = s.charCodeAt(i);
    i++;
    if (src === 0xff) mem[dst + 1] = -1;
    else mem[dst + 1] = mem[src + 1];
  }
}

function caml_new_lex_engine(tbl, start_state, lexbuf) {
  var lex_buffer = 2;
  var lex_buffer_len = 3;
  var lex_start_pos = 5;
  var lex_curr_pos = 6;
  var lex_last_pos = 7;
  var lex_last_action = 8;
  var lex_eof_reached = 9;
  var lex_mem = 10;
  var lex_base = 1;
  var lex_backtrk = 2;
  var lex_default = 3;
  var lex_trans = 4;
  var lex_check = 5;
  var lex_base_code = 6;
  var lex_backtrk_code = 7;
  var lex_default_code = 8;
  var lex_trans_code = 9;
  var lex_check_code = 10;
  var lex_code = 11;

  if (!tbl.lex_default) {
    tbl.lex_base = caml_lex_array(tbl[lex_base]);
    tbl.lex_backtrk = caml_lex_array(tbl[lex_backtrk]);
    tbl.lex_check = caml_lex_array(tbl[lex_check]);
    tbl.lex_trans = caml_lex_array(tbl[lex_trans]);
    tbl.lex_default = caml_lex_array(tbl[lex_default]);
  }
  if (!tbl.lex_default_code) {
    tbl.lex_base_code = caml_lex_array(tbl[lex_base_code]);
    tbl.lex_backtrk_code = caml_lex_array(tbl[lex_backtrk_code]);
    tbl.lex_check_code = caml_lex_array(tbl[lex_check_code]);
    tbl.lex_trans_code = caml_lex_array(tbl[lex_trans_code]);
    tbl.lex_default_code = caml_lex_array(tbl[lex_default_code]);
  }
  if (tbl.lex_code == null)
    tbl.lex_code = caml_jsbytes_of_string(tbl[lex_code]);

  var c,
    state = start_state;

  var buffer = lexbuf[lex_buffer];

  if (state >= 0) {
    /* First entry */
    lexbuf[lex_last_pos] = lexbuf[lex_start_pos] = lexbuf[lex_curr_pos];
    lexbuf[lex_last_action] = -1;
  } else {
    /* Reentry after refill */
    state = -state - 1;
  }
  for (;;) {
    /* Lookup base address or action number for current state */
    var base = tbl.lex_base[state];
    if (base < 0) {
      var pc_off = tbl.lex_base_code[state];
      caml_lex_run_tag(tbl.lex_code, pc_off, lexbuf[lex_mem]);
      return -base - 1;
    }
    /* See if it's a backtrack point */
    var backtrk = tbl.lex_backtrk[state];
    if (backtrk >= 0) {
      var pc_off = tbl.lex_backtrk_code[state];
      caml_lex_run_tag(tbl.lex_code, pc_off, lexbuf[lex_mem]);
      lexbuf[lex_last_pos] = lexbuf[lex_curr_pos];
      lexbuf[lex_last_action] = backtrk;
    }
    /* See if we need a refill */
    if (lexbuf[lex_curr_pos] >= lexbuf[lex_buffer_len]) {
      if (lexbuf[lex_eof_reached] === 0) return -state - 1;
      else c = 256;
    } else {
      /* Read next input char */
      c = caml_bytes_unsafe_get(buffer, lexbuf[lex_curr_pos]);
      lexbuf[lex_curr_pos]++;
    }
    /* Determine next state */
    var pstate = state;
    if (tbl.lex_check[base + c] === state) state = tbl.lex_trans[base + c];
    else state = tbl.lex_default[state];
    /* If no transition on this char, return to last backtrack point */
    if (state < 0) {
      lexbuf[lex_curr_pos] = lexbuf[lex_last_pos];
      if (lexbuf[lex_last_action] === -1) caml_failwith("lexing: empty token");
      else return lexbuf[lex_last_action];
    } else {
      /* If some transition, get and perform memory moves */
      var base_code = tbl.lex_base_code[pstate],
        pc_off;
      if (tbl.lex_check_code[base_code + c] === pstate)
        pc_off = tbl.lex_trans_code[base_code + c];
      else pc_off = tbl.lex_default_code[pstate];
      if (pc_off > 0)
        caml_lex_run_mem(
          tbl.lex_code,
          pc_off,
          lexbuf[lex_mem],
          lexbuf[lex_curr_pos],
        );
      /* Erase the EOF condition only if the EOF pseudo-character was
         consumed by the automaton (i.e. there was no backtrack above)
      */
      if (c === 256) lexbuf[lex_eof_reached] = 0;
    }
  }
}
