local t=require(script.Parent.LuaZ)local f={}f.RESERVED="\084\075\095\065\078\068 \097\110\100\n\084\075\095\066\082\069\065\075 \098\114\101\097\107\n\084\075\095\068\079 \100\111\n\084\075\095\069\076\083\069 \101\108\115\101\n\084\075\095\069\076\083\069\073\070 \101\108\115\101\105\102\n\084\075\095\069\078\068 \101\110\100\n\084\075\095\070\065\076\083\069 \102\097\108\115\101\n\084\075\095\070\079\082 \102\111\114\n\084\075\095\070\085\078\067\084\073\079\078 \102\117\110\099\116\105\111\110\n\084\075\095\073\070 \105\102\n\084\075\095\073\078 \105\110\n\084\075\095\076\079\067\065\076 \108\111\099\097\108\n\084\075\095\078\073\076 \110\105\108\n\084\075\095\078\079\084 \110\111\116\n\084\075\095\079\082 \111\114\n\084\075\095\082\069\080\069\065\084 \114\101\112\101\097\116\n\084\075\095\082\069\084\085\082\078 \114\101\116\117\114\110\n\084\075\095\084\072\069\078 \116\104\101\110\n\084\075\095\084\082\085\069 \116\114\117\101\n\084\075\095\085\078\084\073\076 \117\110\116\105\108\n\084\075\095\087\072\073\076\069 \119\104\105\108\101\n\084\075\095\067\079\078\067\065\084 \046\046\n\084\075\095\068\079\084\083 \046\046\046\n\084\075\095\069\081 \061\061\n\084\075\095\071\069 \062\061\n\084\075\095\076\069 \060\061\n\084\075\095\078\069 ~\061\n\084\075\095\078\065\077\069 \060\110\097\109\101\062\n\084\075\095\078\085\077\066\069\082 \060\110\117\109\098\101\114\062\n\084\075\095\083\084\082\073\078\071 \060\115\116\114\105\110\103\062\n\084\075\095\069\079\083 \060\101\111\102\062"f.MAXSRC=80 f.MAX_INT=2147483645 f.LUA_QS="\'\037\115\'"f.LUA_COMPAT_LSTR=1 function f.init(t)local f,X={},{}for t in string.gmatch(t.RESERVED,"\091\094\n\093\043")do local S,U,I,d=string.find(t,"\040\037\083\043\041\037\115\043\040\037\083\043\041")f[I]=d X[d]=I end t.tokens=f t.enums=X end function f.chunkid(X,t,f)local S local U=string.sub(t,1,1)if U=="\061"then S=string.sub(t,2,f)else if U=="\064"then t=string.sub(t,2)f=f-7 local X=#t S=""if X>f then t=string.sub(t,(1+X)-f)S=S.."\046\046\046"end S=S..t else local X=string.find(t,"\091\n\r\093")X=X and X-1 or#t f=f-16 if X>f then X=f end S="\091\115\116\114\105\110\103 \""if X<#t then S=S..(string.sub(t,1,X).."\046\046\046")else S=S..t end S=S.."\"\093"end end return S end function f.token2str(X,t,f)if string.sub(f,1,3)~="\084\075\095"then if string.find(f,"\037\099")then return string.format("\099\104\097\114\040\037\100\041",string.byte(f))end return f else end return X.tokens[f]end function f.lexerror(S,t,f,X)local function U(t,f)if f=="\084\075\095\078\065\077\069"or f=="\084\075\095\083\084\082\073\078\071"or f=="\084\075\095\078\085\077\066\069\082"then return t.buff else return S:token2str(t,f)end end local I=S:chunkid(t.source,S.MAXSRC)local d=string.format("\037\115\058\037\100\058 \037\115",I,t.linenumber,f)if X then d=string.format("\037\115 \110\101\097\114 "..S.LUA_QS,d,U(t,X))end error(d)end function f.syntaxerror(X,t,f)X:lexerror(t,f,t.t.token)end function f.currIsNewline(f,t)return t.current=="\n"or t.current=="\r"end function f.inclinenumber(f,t)local X=t.current f:nextc(t)if f:currIsNewline(t)and t.current~=X then f:nextc(t)end t.linenumber=t.linenumber+1 if t.linenumber>=f.MAX_INT then f:syntaxerror(t,"\099\104\117\110\107 \104\097\115 \116\111\111 \109\097\110\121 \108\105\110\101\115")end end function f.setinput(U,t,f,X,S)if not f then f={}end if not f.lookahead then f.lookahead={}end if not f.t then f.t={}end f.decpoint="\046"f.L=t f.lookahead.token="\084\075\095\069\079\083"f.z=X f.fs=nil f.linenumber=1 f.lastline=1 f.source=S U:nextc(f)end function f.check_next(X,t,f)if not string.find(f,t.current,1,1)then return false end X:save_and_next(t)return true end function f.next(f,t)t.lastline=t.linenumber if t.lookahead.token~="\084\075\095\069\079\083"then t.t.seminfo=t.lookahead.seminfo t.t.token=t.lookahead.token t.lookahead.token="\084\075\095\069\079\083"else t.t.token=f:llex(t,t.t)end end function f.lookahead(f,t)t.lookahead.token=f:llex(t,t.lookahead)end function f.nextc(X,f)local S=t:zgetc(f.z)f.current=S return S end function f.save(X,t,f)local S=t.buff t.buff=S..f end function f.save_and_next(f,t)f:save(t,t.current)return f:nextc(t)end function f.str2d(f,t)local X=tonumber(t)if X then return X end if string.lower(string.sub(t,1,2))=="\048\120"then X=tonumber(t,16)if X then return X end end return nil end function f.buffreplace(S,t,f,X)local U,I="",t.buff for t=1,#I,1 do local S=string.sub(I,t,t)if S==f then S=X end U=U..S end t.buff=U end function f.trydecpoint(X,t,f)local S=t.decpoint X:buffreplace(t,S,t.decpoint)local U=X:str2d(t.buff)f.seminfo=U if not U then X:buffreplace(t,t.decpoint,"\046")X:lexerror(t,"\109\097\108\102\111\114\109\101\100 \110\117\109\098\101\114","\084\075\095\078\085\077\066\069\082")end end function f.read_numeral(X,t,f)repeat X:save_and_next(t)until string.find(t.current,"\037\068")and t.current~="\046"if X:check_next(t,"\069\101")then X:check_next(t,"\043-")end while string.find(t.current,"\094\037\119\036")or t.current=="\095"do X:save_and_next(t)end X:buffreplace(t,"\046",t.decpoint)local S=X:str2d(t.buff)f.seminfo=S if not S then X:trydecpoint(t,f)end end function f.skip_sep(f,t)local X=0 local S=t.current f:save_and_next(t)while t.current=="\061"do f:save_and_next(t)X=X+1 end return t.current==S and X or-X-1 end function f.read_long_string(S,t,f,X)local U=0 S:save_and_next(t)if S:currIsNewline(t)then S:inclinenumber(t)end while true do local I=t.current if I=="\069\079\090"then S:lexerror(t,f and"\117\110\102\105\110\105\115\104\101\100 \108\111\110\103 \115\116\114\105\110\103"or"\117\110\102\105\110\105\115\104\101\100 \108\111\110\103 \099\111\109\109\101\110\116","\084\075\095\069\079\083")elseif I=="\091"then if S.LUA_COMPAT_LSTR then if S:skip_sep(t)==X then S:save_and_next(t)U=U+1 if S.LUA_COMPAT_LSTR==1 then if X==0 then S:lexerror(t,"\110\101\115\116\105\110\103 \111\102 \091\091\046\046\046\093\093 \105\115 \100\101\112\114\101\099\097\116\101\100","\091")end end end end elseif I=="\093"then if S:skip_sep(t)==X then S:save_and_next(t)if S.LUA_COMPAT_LSTR and S.LUA_COMPAT_LSTR==2 then U=U-1 if X==0 and U>=0 then break end end break end elseif S:currIsNewline(t)then S:save(t,"\n")S:inclinenumber(t)if not f then t.buff=""end else if f then S:save_and_next(t)else S:nextc(t)end end end if f then local S=3+X f.seminfo=string.sub(t.buff,S,-S)end end function f.read_string(S,t,f,X)S:save_and_next(t)while t.current~=f do local f=t.current if f=="\069\079\090"then S:lexerror(t,"\117\110\102\105\110\105\115\104\101\100 \115\116\114\105\110\103","\084\075\095\069\079\083")elseif S:currIsNewline(t)then S:lexerror(t,"\117\110\102\105\110\105\115\104\101\100 \115\116\114\105\110\103","\084\075\095\083\084\082\073\078\071")elseif f=="\092"then f=S:nextc(t)if S:currIsNewline(t)then S:save(t,"\n")S:inclinenumber(t)elseif f~="\069\079\090"then local X=string.find("\097\098\102\110\114\116\118",f,1,1)if X then S:save(t,string.sub("\a\b\012\n\r\t\v",X,X))S:nextc(t)elseif not string.find(f,"\037\100")then S:save_and_next(t)else f,X=0,0 repeat f=10*f+t.current S:nextc(t)X=X+1 until X>=3 or not string.find(t.current,"\037\100")if f>255 then S:lexerror(t,"\101\115\099\097\112\101 \115\101\113\117\101\110\099\101 \116\111\111 \108\097\114\103\101","\084\075\095\083\084\082\073\078\071")end S:save(t,string.char(f))end end else S:save_and_next(t)end end S:save_and_next(t)X.seminfo=string.sub(t.buff,2,-2)end function f.llex(X,t,f)t.buff=""while true do local S=t.current if X:currIsNewline(t)then X:inclinenumber(t)elseif S=="-"then S=X:nextc(t)if S~="-"then return"-"end local f=-1 if X:nextc(t)=="\091"then f=X:skip_sep(t)t.buff=""end if f>=0 then X:read_long_string(t,nil,f)t.buff=""else while not X:currIsNewline(t)and t.current~="\069\079\090"do X:nextc(t)end end elseif S=="\091"then local S=X:skip_sep(t)if S>=0 then X:read_long_string(t,f,S)return"\084\075\095\083\084\082\073\078\071"elseif S==-1 then return"\091"else X:lexerror(t,"\105\110\118\097\108\105\100 \108\111\110\103 \115\116\114\105\110\103 \100\101\108\105\109\105\116\101\114","\084\075\095\083\084\082\073\078\071")end elseif S=="\061"then S=X:nextc(t)if S~="\061"then return"\061"else X:nextc(t)return"\084\075\095\069\081"end elseif S=="\060"then S=X:nextc(t)if S~="\061"then return"\060"else X:nextc(t)return"\084\075\095\076\069"end elseif S=="\062"then S=X:nextc(t)if S~="\061"then return"\062"else X:nextc(t)return"\084\075\095\071\069"end elseif S=="~"then S=X:nextc(t)if S~="\061"then return"~"else X:nextc(t)return"\084\075\095\078\069"end elseif S=="\""or S=="\'"then X:read_string(t,S,f)return"\084\075\095\083\084\082\073\078\071"elseif S=="\046"then S=X:save_and_next(t)if X:check_next(t,"\046")then if X:check_next(t,"\046")then return"\084\075\095\068\079\084\083"else return"\084\075\095\067\079\078\067\065\084"end elseif not string.find(S,"\037\100")then return"\046"else X:read_numeral(t,f)return"\084\075\095\078\085\077\066\069\082"end elseif S=="\069\079\090"then return"\084\075\095\069\079\083"else if string.find(S,"\037\115")then X:nextc(t)elseif string.find(S,"\037\100")then X:read_numeral(t,f)return"\084\075\095\078\085\077\066\069\082"elseif string.find(S,"\091\095\037\097\093")then repeat S=X:save_and_next(t)until S=="\069\079\090"or not string.find(S,"\091\095\037\119\093")local U=t.buff local I=X.enums[U]if I then return I end f.seminfo=U return"\084\075\095\078\065\077\069"else X:nextc(t)return S end end end end return f
--[[--------------------------------------------------------------------

  llex.lua
  Lua lexical analyzer in Lua
  This file is part of Yueliang.

  Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
  The COPYRIGHT file describes the conditions
  under which this software may be distributed.

  See the ChangeLog for more information.

----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- Notes:
-- * intended to 'imitate' llex.c code; performance is not a concern
-- * tokens are strings; code structure largely retained
-- * deleted stuff (compared to llex.c) are noted, comments retained
-- * nextc() returns the currently read character to simplify coding
--   here; next() in llex.c does not return anything
-- * compatibility code is marked with "--#" comments
--
-- Added:
-- * luaX:chunkid (function luaO_chunkid from lobject.c)
-- * luaX:str2d (function luaO_str2d from lobject.c)
-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
--
-- To use the lexer:
-- (1) luaX:init() to initialize the lexer
-- (2) luaX:setinput() to set the input stream to lex
-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
--     until "TK_EOS": luaX:next()
-- * since EOZ is returned as a string, be careful when regexp testing
--
-- Not implemented:
-- * luaX_newstring: not required by this Lua implementation
-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
--   in the interest of performance
-- * locale-aware number handling is largely redundant as Lua's
--   tonumber() function is already capable of this
--
-- Changed in 5.1.x:
-- * TK_NAME token order moved down
-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
-- * token struct renamed to lower case (LS -> ls)
-- * LexState struct: removed nestlevel, added decpoint
-- * error message functions have been greatly simplified
-- * token2string renamed to luaX_tokens, exposed in llex.h
-- * lexer now handles all kinds of newlines, including CRLF
-- * shbang first line handling removed from luaX:setinput;
--   it is now done in lauxlib.c (luaL_loadfile)
-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
-- * checkbuffer(ls, len) macro deleted
-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
--   luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
-- * luaX:read_numeral is now more promiscuous in slurping characters;
--   hexadecimal numbers was added, locale-aware decimal points too
-- * luaX:skip_sep is new; used by luaX:read_long_string
-- * luaX:read_long_string handles new-style long blocks, with some
--   optional compatibility code
-- * luaX:llex: parts changed to support new-style long blocks
-- * luaX:llex: readname functionality has been folded in
-- * luaX:llex: removed test for control characters
--
--------------------------------------------------------------------]]

local luaZ = require(script.Parent.LuaZ)

local luaX = {}

-- FIRST_RESERVED is not required as tokens are manipulated as strings
-- TOKEN_LEN deleted; maximum length of a reserved word not needed

------------------------------------------------------------------------
-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
------------------------------------------------------------------------

-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
-- other terminal symbols: TK_NAME to TK_EOS
luaX.RESERVED = [[
TK_AND and
TK_BREAK break
TK_DO do
TK_ELSE else
TK_ELSEIF elseif
TK_END end
TK_FALSE false
TK_FOR for
TK_FUNCTION function
TK_IF if
TK_IN in
TK_LOCAL local
TK_NIL nil
TK_NOT not
TK_OR or
TK_REPEAT repeat
TK_RETURN return
TK_THEN then
TK_TRUE true
TK_UNTIL until
TK_WHILE while
TK_CONCAT ..
TK_DOTS ...
TK_EQ ==
TK_GE >=
TK_LE <=
TK_NE ~=
TK_NAME <name>
TK_NUMBER <number>
TK_STRING <string>
TK_EOS <eof>]]

-- NUM_RESERVED is not required; number of reserved words

--[[--------------------------------------------------------------------
-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
-- so that lexer functions can use its table element, ls.t.seminfo
--
-- SemInfo (struct no longer needed, a mixed-type value is used)
--
-- Token (struct of ls.t and ls.lookahead):
--   token  -- token symbol
--   seminfo  -- semantics information
--
-- LexState (struct of ls; ls is initialized by luaX:setinput):
--   current  -- current character (charint)
--   linenumber  -- input line counter
--   lastline  -- line of last token 'consumed'
--   t  -- current token (table: struct Token)
--   lookahead  -- look ahead token (table: struct Token)
--   fs  -- 'FuncState' is private to the parser
--   L -- LuaState
--   z  -- input stream
--   buff  -- buffer for tokens
--   source  -- current source name
--   decpoint -- locale decimal point
--   nestlevel  -- level of nested non-terminals
----------------------------------------------------------------------]]

-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init

luaX.MAXSRC = 80
luaX.MAX_INT = 2147483645       -- constants from elsewhere (see above)
luaX.LUA_QS = "'%s'"
luaX.LUA_COMPAT_LSTR = 1
--luaX.MAX_SIZET = 4294967293

------------------------------------------------------------------------
-- initialize lexer
-- * original luaX_init has code to create and register token strings
-- * luaX.tokens: TK_* -> token
-- * luaX.enums:  token -> TK_* (used in luaX:llex)
------------------------------------------------------------------------
function luaX:init()
  local tokens, enums = {}, {}
  for v in string.gmatch(self.RESERVED, "[^\n]+") do
    local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
    tokens[tok] = str
    enums[str] = tok
  end
  self.tokens = tokens
  self.enums = enums
end

------------------------------------------------------------------------
-- returns a suitably-formatted chunk name or id
-- * from lobject.c, used in llex.c and ldebug.c
-- * the result, out, is returned (was first argument)
------------------------------------------------------------------------
function luaX:chunkid(source, bufflen)
  local out
  local first = string.sub(source, 1, 1)
  if first == "=" then
    out = string.sub(source, 2, bufflen)  -- remove first char
  else  -- out = "source", or "...source"
    if first == "@" then
      source = string.sub(source, 2)  -- skip the '@'
      bufflen = bufflen - #" '...' "
      local l = #source
      out = ""
      if l > bufflen then
        source = string.sub(source, 1 + l - bufflen)  -- get last part of file name
        out = out.."..."
      end
      out = out..source
    else  -- out = [string "string"]
      local len = string.find(source, "[\n\r]")  -- stop at first newline
      len = len and (len - 1) or #source
      bufflen = bufflen - #(" [string \"...\"] ")
      if len > bufflen then len = bufflen end
      out = "[string \""
      if len < #source then  -- must truncate?
        out = out..string.sub(source, 1, len).."..."
      else
        out = out..source
      end
      out = out.."\"]"
    end
  end
  return out
end

--[[--------------------------------------------------------------------
-- Support functions for lexer
-- * all lexer errors eventually reaches lexerror:
     syntaxerror -> lexerror
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- look up token and return keyword if found (also called by parser)
------------------------------------------------------------------------
function luaX:token2str(ls, token)
  if string.sub(token, 1, 3) ~= "TK_" then
    if string.find(token, "%c") then
      return string.format("char(%d)", string.byte(token))
    end
    return token
  else
  end
    return self.tokens[token]
end

------------------------------------------------------------------------
-- throws a lexer error
-- * txtToken has been made local to luaX:lexerror
-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
------------------------------------------------------------------------
function luaX:lexerror(ls, msg, token)
  local function txtToken(ls, token)
    if token == "TK_NAME" or
       token == "TK_STRING" or
       token == "TK_NUMBER" then
      return ls.buff
    else
      return self:token2str(ls, token)
    end
  end
  local buff = self:chunkid(ls.source, self.MAXSRC)
  local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
  if token then
    msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
  end
  -- luaD_throw(ls->L, LUA_ERRSYNTAX)
  error(msg)
end

------------------------------------------------------------------------
-- throws a syntax error (mainly called by parser)
-- * ls.t.token has to be set by the function calling luaX:llex
--   (see luaX:next and luaX:lookahead elsewhere in this file)
------------------------------------------------------------------------
function luaX:syntaxerror(ls, msg)
  self:lexerror(ls, msg, ls.t.token)
end

------------------------------------------------------------------------
-- move on to next line
------------------------------------------------------------------------
function luaX:currIsNewline(ls)
  return ls.current == "\n" or ls.current == "\r"
end

function luaX:inclinenumber(ls)
  local old = ls.current
  -- lua_assert(currIsNewline(ls))
  self:nextc(ls)  -- skip '\n' or '\r'
  if self:currIsNewline(ls) and ls.current ~= old then
    self:nextc(ls)  -- skip '\n\r' or '\r\n'
  end
  ls.linenumber = ls.linenumber + 1
  if ls.linenumber >= self.MAX_INT then
    self:syntaxerror(ls, "chunk has too many lines")
  end
end

------------------------------------------------------------------------
-- initializes an input stream for lexing
-- * if ls (the lexer state) is passed as a table, then it is filled in,
--   otherwise it has to be retrieved as a return value
-- * LUA_MINBUFFER not used; buffer handling not required any more
------------------------------------------------------------------------
function luaX:setinput(L, ls, z, source)
  if not ls then ls = {} end  -- create struct
  if not ls.lookahead then ls.lookahead = {} end
  if not ls.t then ls.t = {} end
  ls.decpoint = "."
  ls.L = L
  ls.lookahead.token = "TK_EOS"  -- no look-ahead token
  ls.z = z
  ls.fs = nil
  ls.linenumber = 1
  ls.lastline = 1
  ls.source = source
  self:nextc(ls)  -- read first char
end

--[[--------------------------------------------------------------------
-- LEXICAL ANALYZER
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- checks if current character read is found in the set 'set'
------------------------------------------------------------------------
function luaX:check_next(ls, set)
  if not string.find(set, ls.current, 1, 1) then
    return false
  end
  self:save_and_next(ls)
  return true
end

------------------------------------------------------------------------
-- retrieve next token, checking the lookahead buffer if necessary
-- * note that the macro next(ls) in llex.c is now luaX:nextc
-- * utilized used in lparser.c (various places)
------------------------------------------------------------------------
function luaX:next(ls)
  ls.lastline = ls.linenumber
  if ls.lookahead.token ~= "TK_EOS" then  -- is there a look-ahead token?
    -- this must be copy-by-value
    ls.t.seminfo = ls.lookahead.seminfo  -- use this one
    ls.t.token = ls.lookahead.token
    ls.lookahead.token = "TK_EOS"  -- and discharge it
  else
    ls.t.token = self:llex(ls, ls.t)  -- read next token
  end
end

------------------------------------------------------------------------
-- fill in the lookahead buffer
-- * utilized used in lparser.c:constructor
------------------------------------------------------------------------
function luaX:lookahead(ls)
  -- lua_assert(ls.lookahead.token == "TK_EOS")
  ls.lookahead.token = self:llex(ls, ls.lookahead)
end

------------------------------------------------------------------------
-- gets the next character and returns it
-- * this is the next() macro in llex.c; see notes at the beginning
------------------------------------------------------------------------
function luaX:nextc(ls)
  local c = luaZ:zgetc(ls.z)
  ls.current = c
  return c
end

------------------------------------------------------------------------
-- saves the given character into the token buffer
-- * buffer handling code removed, not used in this implementation
-- * test for maximum token buffer length not used, makes things faster
------------------------------------------------------------------------

function luaX:save(ls, c)
  local buff = ls.buff
  -- if you want to use this, please uncomment luaX.MAX_SIZET further up
  --if #buff > self.MAX_SIZET then
  --  self:lexerror(ls, "lexical element too long")
  --end
  ls.buff = buff..c
end

------------------------------------------------------------------------
-- save current character into token buffer, grabs next character
-- * like luaX:nextc, returns the character read for convenience
------------------------------------------------------------------------
function luaX:save_and_next(ls)
  self:save(ls, ls.current)
  return self:nextc(ls)
end

------------------------------------------------------------------------
-- LUA_NUMBER
-- * luaX:read_numeral is the main lexer function to read a number
-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
------------------------------------------------------------------------

------------------------------------------------------------------------
-- string to number converter (was luaO_str2d from lobject.c)
-- * returns the number, nil if fails (originally returns a boolean)
-- * conversion function originally lua_str2number(s,p), a macro which
--   maps to the strtod() function by default (from luaconf.h)
------------------------------------------------------------------------
function luaX:str2d(s)
  local result = tonumber(s)
  if result then return result end
  -- conversion failed
  if string.lower(string.sub(s, 1, 2)) == "0x" then  -- maybe an hexadecimal constant?
    result = tonumber(s, 16)
    if result then return result end  -- most common case
    -- Was: invalid trailing characters?
    -- In C, this function then skips over trailing spaces.
    -- true is returned if nothing else is found except for spaces.
    -- If there is still something else, then it returns a false.
    -- All this is not necessary using Lua's tonumber.
  end
  return nil
end

------------------------------------------------------------------------
-- single-character replacement, for locale-aware decimal points
------------------------------------------------------------------------
function luaX:buffreplace(ls, from, to)
  local result, buff = "", ls.buff
  for p = 1, #buff do
    local c = string.sub(buff, p, p)
    if c == from then c = to end
    result = result..c
  end
  ls.buff = result
end

------------------------------------------------------------------------
-- Attempt to convert a number by translating '.' decimal points to
-- the decimal point character used by the current locale. This is not
-- needed in Yueliang as Lua's tonumber() is already locale-aware.
-- Instead, the code is here in case the user implements localeconv().
------------------------------------------------------------------------
function luaX:trydecpoint(ls, Token)
  -- format error: try to update decimal point separator
  local old = ls.decpoint
  -- translate the following to Lua if you implement localeconv():
  -- struct lconv *cv = localeconv();
  -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
  self:buffreplace(ls, old, ls.decpoint)  -- try updated decimal separator
  local seminfo = self:str2d(ls.buff)
  Token.seminfo = seminfo
  if not seminfo then
    -- format error with correct decimal point: no more options
    self:buffreplace(ls, ls.decpoint, ".")  -- undo change (for error message)
    self:lexerror(ls, "malformed number", "TK_NUMBER")
  end
end

------------------------------------------------------------------------
-- main number conversion function
-- * "^%w$" needed in the scan in order to detect "EOZ"
------------------------------------------------------------------------
function luaX:read_numeral(ls, Token)
  -- lua_assert(string.find(ls.current, "%d"))
  repeat
    self:save_and_next(ls)
  until string.find(ls.current, "%D") and ls.current ~= "."
  if self:check_next(ls, "Ee") then  -- 'E'?
    self:check_next(ls, "+-")  -- optional exponent sign
  end
  while string.find(ls.current, "^%w$") or ls.current == "_" do
    self:save_and_next(ls)
  end
  self:buffreplace(ls, ".", ls.decpoint)  -- follow locale for decimal point
  local seminfo = self:str2d(ls.buff)
  Token.seminfo = seminfo
  if not seminfo then  -- format error?
    self:trydecpoint(ls, Token) -- try to update decimal point separator
  end
end

------------------------------------------------------------------------
-- count separators ("=") in a long string delimiter
-- * used by luaX:read_long_string
------------------------------------------------------------------------
function luaX:skip_sep(ls)
  local count = 0
  local s = ls.current
  -- lua_assert(s == "[" or s == "]")
  self:save_and_next(ls)
  while ls.current == "=" do
    self:save_and_next(ls)
    count = count + 1
  end
  return (ls.current == s) and count or (-count) - 1
end

------------------------------------------------------------------------
-- reads a long string or long comment
------------------------------------------------------------------------
function luaX:read_long_string(ls, Token, sep)
  local cont = 0
  self:save_and_next(ls)  -- skip 2nd '['
  if self:currIsNewline(ls) then  -- string starts with a newline?
    self:inclinenumber(ls)  -- skip it
  end
  while true do
    local c = ls.current
    if c == "EOZ" then
      self:lexerror(ls, Token and "unfinished long string" or
                    "unfinished long comment", "TK_EOS")
    elseif c == "[" then
      --# compatibility code start
      if self.LUA_COMPAT_LSTR then
        if self:skip_sep(ls) == sep then
          self:save_and_next(ls)  -- skip 2nd '['
          cont = cont + 1
          --# compatibility code start
          if self.LUA_COMPAT_LSTR == 1 then
            if sep == 0 then
              self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
            end
          end
          --# compatibility code end
        end
      end
      --# compatibility code end
    elseif c == "]" then
      if self:skip_sep(ls) == sep then
        self:save_and_next(ls)  -- skip 2nd ']'
        --# compatibility code start
        if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
          cont = cont - 1
          if sep == 0 and cont >= 0 then break end
        end
        --# compatibility code end
        break
      end
    elseif self:currIsNewline(ls) then
      self:save(ls, "\n")
      self:inclinenumber(ls)
      if not Token then ls.buff = "" end -- avoid wasting space
    else  -- default
      if Token then
        self:save_and_next(ls)
      else
        self:nextc(ls)
      end
    end--if c
  end--while
  if Token then
    local p = 3 + sep
    Token.seminfo = string.sub(ls.buff, p, -p)
  end
end

------------------------------------------------------------------------
-- reads a string
-- * has been restructured significantly compared to the original C code
------------------------------------------------------------------------

function luaX:read_string(ls, del, Token)
  self:save_and_next(ls)
  while ls.current ~= del do
    local c = ls.current
    if c == "EOZ" then
      self:lexerror(ls, "unfinished string", "TK_EOS")
    elseif self:currIsNewline(ls) then
      self:lexerror(ls, "unfinished string", "TK_STRING")
    elseif c == "\\" then
      c = self:nextc(ls)  -- do not save the '\'
      if self:currIsNewline(ls) then  -- go through
        self:save(ls, "\n")
        self:inclinenumber(ls)
      elseif c ~= "EOZ" then -- will raise an error next loop
        -- escapes handling greatly simplified here:
        local i = string.find("abfnrtv", c, 1, 1)
        if i then
          self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
          self:nextc(ls)
        elseif not string.find(c, "%d") then
          self:save_and_next(ls)  -- handles \\, \", \', and \?
        else  -- \xxx
          c, i = 0, 0
          repeat
            c = 10 * c + ls.current
            self:nextc(ls)
            i = i + 1
          until i >= 3 or not string.find(ls.current, "%d")
          if c > 255 then  -- UCHAR_MAX
            self:lexerror(ls, "escape sequence too large", "TK_STRING")
          end
          self:save(ls, string.char(c))
        end
      end
    else
      self:save_and_next(ls)
    end--if c
  end--while
  self:save_and_next(ls)  -- skip delimiter
  Token.seminfo = string.sub(ls.buff, 2, -2)
end

------------------------------------------------------------------------
-- main lexer function
------------------------------------------------------------------------
function luaX:llex(ls, Token)
  ls.buff = ""
  while true do
    local c = ls.current
    ----------------------------------------------------------------
    if self:currIsNewline(ls) then
      self:inclinenumber(ls)
    ----------------------------------------------------------------
    elseif c == "-" then
      c = self:nextc(ls)
      if c ~= "-" then return "-" end
      -- else is a comment
      local sep = -1
      if self:nextc(ls) == '[' then
        sep = self:skip_sep(ls)
        ls.buff = ""  -- 'skip_sep' may dirty the buffer
      end
      if sep >= 0 then
        self:read_long_string(ls, nil, sep)  -- long comment
        ls.buff = ""
      else  -- else short comment
        while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
          self:nextc(ls)
        end
      end
    ----------------------------------------------------------------
    elseif c == "[" then
      local sep = self:skip_sep(ls)
      if sep >= 0 then
        self:read_long_string(ls, Token, sep)
        return "TK_STRING"
      elseif sep == -1 then
        return "["
      else
        self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
      end
    ----------------------------------------------------------------
    elseif c == "=" then
      c = self:nextc(ls)
      if c ~= "=" then return "="
      else self:nextc(ls); return "TK_EQ" end
    ----------------------------------------------------------------
    elseif c == "<" then
      c = self:nextc(ls)
      if c ~= "=" then return "<"
      else self:nextc(ls); return "TK_LE" end
    ----------------------------------------------------------------
    elseif c == ">" then
      c = self:nextc(ls)
      if c ~= "=" then return ">"
      else self:nextc(ls); return "TK_GE" end
    ----------------------------------------------------------------
    elseif c == "~" then
      c = self:nextc(ls)
      if c ~= "=" then return "~"
      else self:nextc(ls); return "TK_NE" end
    ----------------------------------------------------------------
    elseif c == "\"" or c == "'" then
      self:read_string(ls, c, Token)
      return "TK_STRING"
    ----------------------------------------------------------------
    elseif c == "." then
      c = self:save_and_next(ls)
      if self:check_next(ls, ".") then
        if self:check_next(ls, ".") then
          return "TK_DOTS"   -- ...
        else return "TK_CONCAT"   -- ..
        end
      elseif not string.find(c, "%d") then
        return "."
      else
        self:read_numeral(ls, Token)
        return "TK_NUMBER"
      end
    ----------------------------------------------------------------
    elseif c == "EOZ" then
      return "TK_EOS"
    ----------------------------------------------------------------
    else  -- default
      if string.find(c, "%s") then
        -- lua_assert(self:currIsNewline(ls))
        self:nextc(ls)
      elseif string.find(c, "%d") then
        self:read_numeral(ls, Token)
        return "TK_NUMBER"
      elseif string.find(c, "[_%a]") then
        -- identifier or reserved word
        repeat
          c = self:save_and_next(ls)
        until c == "EOZ" or not string.find(c, "[_%w]")
        local ts = ls.buff
        local tok = self.enums[ts]
        if tok then return tok end  -- reserved word?
        Token.seminfo = ts
        return "TK_NAME"
      else
        self:nextc(ls)
        return c  -- single-char tokens (+ - / ...)
      end
    ----------------------------------------------------------------
    end--if c
  end--while
end

return luaX