Minify Lua
Minify Lua
MIT License
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
function lookupify(tb)
      for _, v in pairs(tb) do
            tb[v] = true
      end
      return tb
end
function CountTable(tb)
      local c = 0
      for _ in pairs(tb) do c = c + 1 end
      return c
end
local CharacterForEscape = {['r'] = '\r', ['n'] = '\n', ['t'] = '\t', ['"'] = '"',
["'"] = "'", ['\\'] = '\\'}
local AllIdentStartChars = lookupify{'a',     'b',   'c',   'd',   'e',   'f',   'g',   'h',   'i',
                                     'j',     'k',   'l',   'm',   'n',   'o',   'p',   'q',   'r',
                                     's',     't',   'u',   'v',   'w',   'x',   'y',   'z',
                                     'A',     'B',   'C',   'D',   'E',   'F',   'G',   'H',   'I',
                                     'J',     'K',   'L',   'M',   'N',   'O',   'P',   'Q',   'R',
                                     'S',     'T',   'U',   'V',   'W',   'X',   'Y',   'Z',   '_'}
local AllIdentChars = lookupify{'a',   'b',   'c',   'd',   'e',   'f',   'g',   'h',   'i',
                                'j',   'k',   'l',   'm',   'n',   'o',   'p',   'q',   'r',
                                's',   't',   'u',   'v',   'w',   'x',   'y',   'z',
                                'A',   'B',   'C',   'D',   'E',   'F',   'G',   'H',   'I',
                                'J',   'K',   'L',   'M',   'N',   'O',   'P',   'Q',   'R',
                                'S',   'T',   'U',   'V',   'W',   'X',   'Y',   'Z',   '_',
                                '0',   '1',   '2',   '3',   '4',   '5',   '6',   '7',   '8', '9'}
local Digits = lookupify{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
local HexDigits = lookupify{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                            'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F',
'f'}
local Symbols = lookupify{'+', '-', '*', '/', '^', '%', ',', '{', '}', '[', ']',
'(', ')', ';', '#', '.', ':'}
local EqualSymbols = lookupify{'~', '=', '>', '<'}
local BinaryPriority = {
   ['+'] = {6, 6};
   ['-'] = {6, 6};
   ['*'] = {7, 7};
   ['/'] = {7, 7};
   ['%'] = {7, 7};
   ['^'] = {10, 9};
   ['..'] = {5, 4};
   ['=='] = {3, 3};
   ['~='] = {3, 3};
   ['>'] = {3, 3};
   ['<'] = {3, 3};
   ['>='] = {3, 3};
   ['<='] = {3, 3};
   ['and'] = {2, 2};
   ['or'] = {1, 1};
};
local UnaryPriority = 8
function CreateLuaTokenStream(text)
      -- Tracking for the current position in the buffer, and
      -- the current line / character we are on.
      local p = 1
      local length = #text
-- Error
local olderr = error
local function error(str)
      local q = 1
      local line = 1
      local char = 1
      while q <= p do
            if text:sub(q, q) == '\n' then
                  line = line + 1
                  char = 1
            else
                  char = char + 1
            end
            q = q + 1
      end
      for _, token in pairs(tokenBuffer) do
            print(token.Type.."<"..token.Source..">")
      end
      olderr("file<"..line..":"..char..">: "..str)
end
-- Add token
local whiteStart = 1
local tokenStart = 1
local function token(type)
      local tk = {
            Type = type;
            LeadingWhite = text:sub(whiteStart, tokenStart-1);
            Source = text:sub(tokenStart, p-1);
      }
      table.insert(tokenBuffer, tk)
      whiteStart = p
      tokenStart = p
      return tk
end
function CreateLuaParser(text)
      -- Token stream and pointer into it
      local tokens = CreateLuaTokenStream(text)
      -- for _, tok in pairs(tokens) do
      --    print(tok.Type..": "..tok.Source)
      -- end
      local p = 1
     -- Forward decls
     local block;
     local expr;
     -- Expression list
     local function exprlist()
           local exprList = {}
           local commaList = {}
           table.insert(exprList, expr())
           while peek().Source == ',' do
                 table.insert(commaList, get())
                 table.insert(exprList, expr())
           end
           return exprList, commaList
     end
local function prefixexpr()
      local tk = peek()
      if tk.Source == '(' then
            local oparenTk = get()
            local inner = expr()
            local cparenTk = expect('Symbol', ')')
            return MkNode{
                  Type = 'ParenExpr';
                  Expression = inner;
                  Token_OpenParen = oparenTk;
                  Token_CloseParen = cparenTk;
                  GetFirstToken = function(self)
                        return self.Token_OpenParen
                  end;
                  GetLastToken = function(self)
                        return self.Token_CloseParen
                  end;
            }
      elseif tk.Type == 'Ident' then
            return MkNode{
                  Type = 'VariableExpr';
                  Token = get();
                  GetFirstToken = function(self)
                        return self.Token
                  end;
                  GetLastToken = function(self)
                        return self.Token
                  end;
            }
      else
            print(debugMark())
            error(getTokenStartPosition(tk)..": Unexpected symbol")
      end
end
function tableexpr()
      local obrace = expect('Symbol', '{')
      local entries = {}
      local separators = {}
      while peek().Source ~= '}' do
            if peek().Source == '[' then
                  -- Index
                  local obrac = get()
                  local index = expr()
                  local cbrac = expect('Symbol', ']')
                  local eq = expect('Symbol', '=')
                  local value = expr()
                  table.insert(entries, {
                        EntryType = 'Index';
                        Index = index;
                        Value = value;
                        Token_OpenBracket = obrac;
                        Token_CloseBracket = cbrac;
                        Token_Equals = eq;
                  })
            elseif peek().Type == 'Ident' and peek(1).Source == '=' then
                  -- Field
                  local field = get()
                  local eq = get()
                  local value = expr()
                  table.insert(entries, {
                        EntryType = 'Field';
                        Field = field;
                        Value = value;
                        Token_Equals = eq;
                  })
           else
                  -- Value
                  local value = expr()
                  table.insert(entries, {
                        EntryType = 'Value';
                        Value = value;
                  })
           end
-- List of identifiers
local function varlist()
      local varList = {}
      local commaList = {}
      if peek().Type == 'Ident' then
            table.insert(varList, get())
      end
      while peek().Source == ',' do
            table.insert(commaList, get())
            local id = expect('Ident')
            table.insert(varList, id)
      end
      return varList, commaList
end
-- Body
local function blockbody(terminator)
      local body = block()
      local after = peek()
      if after.Type == 'Keyword' and after.Source == terminator then
                     get()
                     return body, after
              else
                     print(after.Type, after.Source)
                     error(getTokenStartPosition(after)..": "..terminator.."
expected.")
              end
     end
     -- Function declaration
     local function funcdecl(isAnonymous)
           local functionKw = get()
           --
           local nameChain;
           local nameChainSeparator;
           --
           if not isAnonymous then
                 nameChain = {}
                 nameChainSeparator = {}
                 --
                 table.insert(nameChain, expect('Ident'))
                 --
                 while peek().Source == '.' do
                       table.insert(nameChainSeparator, get())
                       table.insert(nameChain, expect('Ident'))
                 end
                 if peek().Source == ':' then
                       table.insert(nameChainSeparator, get())
                       table.insert(nameChain, expect('Ident'))
                 end
           end
           --
           local oparenTk = expect('Symbol', '(')
           local argList, argCommaList = varlist()
           local cparenTk = expect('Symbol', ')')
           local fbody, enTk = blockbody('end')
           --
           return MkNode{
                 Type = (isAnonymous and 'FunctionLiteral' or 'FunctionStat');
                 NameChain = nameChain;
                 ArgList = argList;
                 Body = fbody;
                 --
                 Token_Function = functionKw;
                 Token_NameChainSeparator = nameChainSeparator;
                 Token_OpenParen = oparenTk;
                 Token_ArgCommaList = argCommaList;
                 Token_CloseParen = cparenTk;
                 Token_End = enTk;
                 GetFirstToken = function(self)
                       return self.Token_Function
                 end;
                 GetLastToken = function(self)
                       return self.Token_End;
                 end;
           }
     end
           -- Return result
           return curNode
     end
     -- Expression
     expr = function()
           return subexpr(0)
     end
      -- Expression statement
      local function exprstat()
            local ex = primaryexpr()
            if ex.Type == 'MethodExpr' or ex.Type == 'CallExpr' then
                  -- all good, calls can be statements
                  return MkNode{
                        Type = 'CallExprStat';
                        Expression = ex;
                        GetFirstToken = function(self)
                              return self.Expression:GetFirstToken()
                        end;
                        GetLastToken = function(self)
                              return self.Expression:GetLastToken()
                        end;
                  }
            else
                  -- Assignment expr
                  local lhs = {ex}
                  local lhsSeparator = {}
                  while peek().Source == ',' do
                        table.insert(lhsSeparator, get())
                        local lhsPart = primaryexpr()
                        if lhsPart.Type == 'MethodExpr' or lhsPart.Type ==
'CallExpr' then
                              error("Bad left hand side of assignment")
                        end
                        table.insert(lhs, lhsPart)
                  end
                  local eq = expect('Symbol', '=')
                  local rhs = {expr()}
                  local rhsSeparator = {}
                  while peek().Source == ',' do
                        table.insert(rhsSeparator, get())
                        table.insert(rhs, expr())
                  end
                  return MkNode{
                        Type = 'AssignmentStat';
                        Rhs = rhs;
                 Lhs = lhs;
                 Token_Equals = eq;
                 Token_LhsSeparatorList = lhsSeparator;
                 Token_RhsSeparatorList = rhsSeparator;
                 GetFirstToken = function(self)
                       return self.Lhs[1]:GetFirstToken()
                 end;
                 GetLastToken = function(self)
                       return self.Rhs[#self.Rhs]:GetLastToken()
                 end;
            }
      end
end
-- If statement
local function ifstat()
      local ifKw = get()
      local condition = expr()
      local thenKw = expect('Keyword', 'then')
      local ifBody = block()
      local elseClauses = {}
      while peek().Source == 'elseif' or peek().Source == 'else' do
            local elseifKw = get()
            local elseifCondition, elseifThenKw;
            if elseifKw.Source == 'elseif' then
                  elseifCondition = expr()
                  elseifThenKw = expect('Keyword', 'then')
            end
            local elseifBody = block()
            table.insert(elseClauses, {
                  Condition = elseifCondition;
                  Body = elseifBody;
                  --
                  ClauseType = elseifKw.Source;
                  Token = elseifKw;
                  Token_Then = elseifThenKw;
            })
            if elseifKw.Source == 'else' then
                  break
            end
      end
      local enKw = expect('Keyword', 'end')
      return MkNode{
            Type = 'IfStat';
            Condition = condition;
            Body = ifBody;
            ElseClauseList = elseClauses;
            --
            Token_If = ifKw;
            Token_Then = thenKw;
            Token_End = enKw;
            GetFirstToken = function(self)
                  return self.Token_If
            end;
            GetLastToken = function(self)
                  return self.Token_End
            end;
      }
end
-- Do statement
local function dostat()
      local doKw = get()
      local body, enKw = blockbody('end')
      --
      return MkNode{
            Type = 'DoStat';
            Body = body;
            --
            Token_Do = doKw;
            Token_End = enKw;
            GetFirstToken = function(self)
                  return self.Token_Do
            end;
            GetLastToken = function(self)
                  return self.Token_End
            end;
      }
end
-- While statement
local function whilestat()
      local whileKw = get()
      local condition = expr()
      local doKw = expect('Keyword', 'do')
      local body, enKw = blockbody('end')
      --
      return MkNode{
            Type = 'WhileStat';
            Condition = condition;
            Body = body;
            --
            Token_While = whileKw;
            Token_Do = doKw;
            Token_End = enKw;
            GetFirstToken = function(self)
                  return self.Token_While
            end;
            GetLastToken = function(self)
                  return self.Token_End
            end;
      }
end
-- For statement
local function forstat()
      local forKw = get()
      local loopVars, loopVarCommas = varlist()
      local node = {}
      if peek().Source == '=' then
            local eqTk = get()
            local exprList, exprCommaList = exprlist()
            if #exprList < 2 or #exprList > 3 then
                  error("expected 2 or 3 values for range bounds")
            end
            local doTk = expect('Keyword', 'do')
            local body, enTk = blockbody('end')
            return MkNode{
                 Type = 'NumericForStat';
                 VarList = loopVars;
                 RangeList = exprList;
                 Body = body;
                 --
                 Token_For = forKw;
                 Token_VarCommaList = loopVarCommas;
                 Token_Equals = eqTk;
                 Token_RangeCommaList = exprCommaList;
                 Token_Do = doTk;
                 Token_End = enTk;
                 GetFirstToken = function(self)
                       return self.Token_For
                 end;
                 GetLastToken = function(self)
                       return self.Token_End
                 end;
            }
      elseif peek().Source == 'in' then
            local inTk = get()
            local exprList, exprCommaList = exprlist()
            local doTk = expect('Keyword', 'do')
            local body, enTk = blockbody('end')
            return MkNode{
                  Type = 'GenericForStat';
                  VarList = loopVars;
                  GeneratorList = exprList;
                  Body = body;
                  --
                  Token_For = forKw;
                  Token_VarCommaList = loopVarCommas;
                  Token_In = inTk;
                  Token_GeneratorCommaList = exprCommaList;
                  Token_Do = doTk;
                  Token_End = enTk;
                  GetFirstToken = function(self)
                        return self.Token_For
                  end;
                  GetLastToken = function(self)
                        return self.Token_End
                  end;
            }
      else
            error("`=` or in expected")
      end
end
-- Repeat statement
local function repeatstat()
      local repeatKw = get()
      local body, untilTk = blockbody('until')
      local condition = expr()
      return MkNode{
            Type = 'RepeatStat';
            Body = body;
            Condition = condition;
            --
            Token_Repeat = repeatKw;
            Token_Until = untilTk;
                 GetFirstToken = function(self)
                       return self.Token_Repeat
                 end;
                 GetLastToken = function(self)
                       return self.Condition:GetLastToken()
                 end;
           }
     end
      error(getTokenStartPosition(funcStat.Token_NameChainSeparator[1])..": `(`
expected.")
                  end
                  return MkNode{
                        Type = 'LocalFunctionStat';
                        FunctionStat = funcStat;
                        Token_Local = localKw;
                        GetFirstToken = function(self)
                              return self.Token_Local
                        end;
                        GetLastToken = function(self)
                              return self.FunctionStat:GetLastToken()
                        end;
                  }
            elseif peek().Type == 'Ident' then
                  -- Local variable declaration
                  local varList, varCommaList = varlist()
                  local exprList, exprCommaList = {}, {}
                  local eqToken;
                  if peek().Source == '=' then
                        eqToken = get()
                        exprList, exprCommaList = exprlist()
                  end
                  return MkNode{
                        Type = 'LocalVarStat';
                        VarList = varList;
                        ExprList = exprList;
                        Token_Local = localKw;
                        Token_Equals = eqToken;
                        Token_VarCommaList = varCommaList;
                        Token_ExprCommaList = exprCommaList;
                        GetFirstToken = function(self)
                              return self.Token_Local
                        end;
                        GetLastToken = function(self)
                              if #self.ExprList > 0 then
                                    return
self.ExprList[#self.ExprList]:GetLastToken()
                              else
                                    return self.VarList[#self.VarList]
                              end
                        end;
             }
      else
             error("`function` or ident expected")
      end
end
-- Return statement
local function retstat()
      local returnKw = get()
      local exprList;
      local commaList;
      if isBlockFollow() or peek().Source == ';' then
            exprList = {}
            commaList = {}
      else
            exprList, commaList = exprlist()
      end
      return {
            Type = 'ReturnStat';
            ExprList = exprList;
            Token_Return = returnKw;
            Token_CommaList = commaList;
            GetFirstToken = function(self)
                  return self.Token_Return
            end;
            GetLastToken = function(self)
                  if #self.ExprList > 0 then
                        return self.ExprList[#self.ExprList]:GetLastToken()
                  else
                        return self.Token_Return
                  end
            end;
      }
end
-- Break statement
local function breakstat()
      local breakKw = get()
      return {
            Type = 'BreakStat';
            Token_Break = breakKw;
            GetFirstToken = function(self)
                  return self.Token_Break
            end;
            GetLastToken = function(self)
                  return self.Token_Break
            end;
      }
end
-- Expression
local function statement()
      local tok = peek()
      if tok.Source == 'if' then
            return false, ifstat()
      elseif tok.Source == 'while' then
            return false, whilestat()
      elseif tok.Source == 'do' then
            return false, dostat()
            elseif tok.Source == 'for' then
                  return false, forstat()
            elseif tok.Source == 'repeat' then
                  return false, repeatstat()
            elseif tok.Source == 'function' then
                  return false, funcdecl(false)
            elseif tok.Source == 'local' then
                  return false, localdecl()
            elseif tok.Source == 'return' then
                  return true, retstat()
            elseif tok.Source == 'break' then
                  return true, breakstat()
            else
                  return false, exprstat()
            end
      end
      -- Chunk
      block = function()
            local statements = {}
            local semicolons = {}
            local isLast = false
            while not isLast and not isBlockFollow() do
                  -- Parse statement
                  local stat;
                  isLast, stat = statement()
                  table.insert(statements, stat)
                  local next = peek()
                  if next.Type == 'Symbol' and next.Source == ';' then
                        semicolons[#statements] = get()
                  end
            end
            return {
                  Type = 'StatList';
                  StatementList = statements;
                  SemicolonList = semicolons;
                  GetFirstToken = function(self)
                        if #self.StatementList == 0 then
                              return nil
                        else
                              return self.StatementList[1]:GetFirstToken()
                        end
                  end;
                  GetLastToken = function(self)
                        if #self.StatementList == 0 then
                              return nil
                        elseif self.SemicolonList[#self.StatementList] then
                              -- Last token may be one of the semicolon separators
                              return self.SemicolonList[#self.StatementList]
                        else
                              return
self.StatementList[#self.StatementList]:GetLastToken()
                        end
                  end;
            }
      end
      return block()
end
function VisitAst(ast, visitors)
      local ExprType = lookupify{
            'BinopExpr'; 'UnopExpr';
            'NumberLiteral'; 'StringLiteral'; 'NilLiteral'; 'BooleanLiteral';
'VargLiteral';
            'FieldExpr'; 'IndexExpr';
            'MethodExpr'; 'CallExpr';
            'FunctionLiteral';
            'VariableExpr';
            'ParenExpr';
            'TableLiteral';
      }
     visitExpr = function(expr)
           if preVisit(expr) then
                 -- Handler did custom child iteration or blocked child iteration
                 return
           end
           if expr.Type == 'BinopExpr' then
                 visitExpr(expr.Lhs)
                 visitExpr(expr.Rhs)
           elseif expr.Type == 'UnopExpr' then
                 visitExpr(expr.Rhs)
           elseif expr.Type == 'NumberLiteral' or expr.Type == 'StringLiteral' or
                 expr.Type == 'NilLiteral' or expr.Type == 'BooleanLiteral' or
                 expr.Type == 'VargLiteral'
           then
                 -- No children to visit, single token literals
           elseif expr.Type == 'FieldExpr' then
                 visitExpr(expr.Base)
           elseif expr.Type == 'IndexExpr' then
                 visitExpr(expr.Base)
                 visitExpr(expr.Index)
           elseif expr.Type == 'MethodExpr' or expr.Type == 'CallExpr' then
                 visitExpr(expr.Base)
                 if expr.FunctionArguments.CallType == 'ArgCall' then
                       for index, argExpr in pairs(expr.FunctionArguments.ArgList)
do
                              visitExpr(argExpr)
                        end
                  elseif expr.FunctionArguments.CallType == 'TableCall' then
                        visitExpr(expr.FunctionArguments.TableExpr)
                  end
            elseif expr.Type == 'FunctionLiteral' then
                  visitStat(expr.Body)
            elseif expr.Type == 'VariableExpr' then
                  -- No children to visit
            elseif expr.Type == 'ParenExpr' then
                  visitExpr(expr.Expression)
            elseif expr.Type == 'TableLiteral' then
                  for index, entry in pairs(expr.EntryList) do
                        if entry.EntryType == 'Field' then
                              visitExpr(entry.Value)
                        elseif entry.EntryType == 'Index' then
                              visitExpr(entry.Index)
                              visitExpr(entry.Value)
                        elseif entry.EntryType == 'Value' then
                              visitExpr(entry.Value)
                        else
                              assert(false, "unreachable")
                        end
                  end
            else
                  assert(false, "unreachable, type:
"..expr.Type..":"..FormatTable(expr))
            end
            postVisit(expr)
      end
     visitStat = function(stat)
           if preVisit(stat) then
                 -- Handler did custom child iteration or blocked child iteration
                 return
           end
           if stat.Type == 'StatList' then
      for index, ch in pairs(stat.StatementList) do
            visitStat(ch)
      end
elseif stat.Type == 'BreakStat' then
      -- No children to visit
elseif stat.Type == 'ReturnStat' then
      for index, expr in pairs(stat.ExprList) do
            visitExpr(expr)
      end
elseif stat.Type == 'LocalVarStat' then
      if stat.Token_Equals then
            for index, expr in pairs(stat.ExprList) do
                  visitExpr(expr)
            end
      end
elseif stat.Type == 'LocalFunctionStat' then
      visitStat(stat.FunctionStat.Body)
elseif stat.Type == 'FunctionStat' then
      visitStat(stat.Body)
elseif stat.Type == 'RepeatStat' then
      visitStat(stat.Body)
      visitExpr(stat.Condition)
elseif stat.Type == 'GenericForStat' then
      for index, expr in pairs(stat.GeneratorList) do
            visitExpr(expr)
      end
      visitStat(stat.Body)
elseif stat.Type == 'NumericForStat' then
      for index, expr in pairs(stat.RangeList) do
            visitExpr(expr)
      end
      visitStat(stat.Body)
elseif stat.Type == 'WhileStat' then
      visitExpr(stat.Condition)
      visitStat(stat.Body)
elseif stat.Type == 'DoStat' then
      visitStat(stat.Body)
elseif stat.Type == 'IfStat' then
      visitExpr(stat.Condition)
      visitStat(stat.Body)
      for _, clause in pairs(stat.ElseClauseList) do
            if clause.Condition then
                  visitExpr(clause.Condition)
            end
            visitStat(clause.Body)
      end
elseif stat.Type == 'CallExprStat' then
      visitExpr(stat.Expression)
elseif stat.Type == 'AssignmentStat' then
      for index, ex in pairs(stat.Lhs) do
            visitExpr(ex)
      end
      for index, ex in pairs(stat.Rhs) do
            visitExpr(ex)
      end
else
      assert(false, "unreachable")
end
postVisit(stat)
      end
      if StatType[ast.Type] then
            visitStat(ast)
      else
            visitExpr(ast)
      end
end
function AddVariableInfo(ast)
      local globalVars = {}
      local currentScope = nil
      -- Scope management
      local function pushScope()
            currentScope = {
                  ParentScope = currentScope;
                  ChildScopeList = {};
                  VariableList = {};
                  BeginLocation = markLocation();
            }
            if currentScope.ParentScope then
                  currentScope.Depth = currentScope.ParentScope.Depth + 1
                  table.insert(currentScope.ParentScope.ChildScopeList,
currentScope)
            else
                  currentScope.Depth = 1
            end
            function currentScope:GetVar(varName)
                  for _, var in pairs(self.VariableList) do
                        if var.Name == varName then
                              return var
                        end
                  end
                  if self.ParentScope then
                        return self.ParentScope:GetVar(varName)
                  else
                        for _, var in pairs(globalVars) do
                              if var.Name == varName then
                                    return var
                              end
                        end
                  end
            end
      end
      local function popScope()
            local scope = currentScope
      return scope
end
pushScope() -- push initial scope
           -- Then
           return nil
     end
     local function referenceVariable(name, setNameFunc)
           assert(name, "Missing var name")
           local var = getLocalVar(currentScope, name)
           if var then
                 table.insert(var.RenameList, setNameFunc)
           else
                 var = addGlobalReference(name, setNameFunc)
           end
           -- Update the end location of where this variable is used, and
           -- add this location to the list of references to this variable.
           local curLocation = markLocation()
           var.EndLocation = curLocation
           table.insert(var.ReferenceLocationList, var.EndLocation)
           return var
     end
      local visitor = {}
      visitor.FunctionLiteral = {
            -- Function literal adds a new scope and adds the function literal
arguments
            -- as local variables in the scope.
            Pre = function(expr)
                 pushScope()
                 for index, ident in pairs(expr.ArgList) do
                       local var = addLocalVar(ident.Source, function(name)
                             ident.Source = name
                       end, {
                             Type = 'Argument';
                             Index = index;
                       })
                 end
           end;
           Post = function(expr)
                 popScope()
           end;
      }
      visitor.VariableExpr = function(expr)
            -- Variable expression references from existing local varibales
            -- in the current scope, annotating the variable usage with variable
            -- information.
            expr.Variable = referenceVariable(expr.Token.Source, function(newName)
                  expr.Token.Source = newName
            end)
      end
      visitor.StatList = {
            -- StatList adds a new scope
            Pre = function(stat)
                  pushScope()
            end;
            Post = function(stat)
                  popScope()
            end;
      }
      visitor.LocalVarStat = {
            Post = function(stat)
                  -- Local var stat adds the local variables to the current scope
as locals
                  -- We need to visit the subexpressions first, because these new
locals
                  -- will not be in scope for the initialization value expressions.
That is:
                  -- `local bar = bar + 1`
                  -- Is valid code
                  for varNum, ident in pairs(stat.VarList) do
                        addLocalVar(ident.Source, function(name)
                              stat.VarList[varNum].Source = name
                        end, {
                              Type = 'Local';
                        })
                  end
            end;
      }
      visitor.LocalFunctionStat = {
            Pre = function(stat)
                  -- Local function stat adds the function itself to the current
scope as
                  -- a local variable, and creates a new scope with the function
arguments
                  -- as local variables.
                  addLocalVar(stat.FunctionStat.NameChain[1].Source, function(name)
                        stat.FunctionStat.NameChain[1].Source = name
                 end, {
                       Type = 'LocalFunction';
                 })
                 pushScope()
                 for index, ident in pairs(stat.FunctionStat.ArgList) do
                       addLocalVar(ident.Source, function(name)
                             ident.Source = name
                       end, {
                             Type = 'Argument';
                             Index = index;
                       })
                 end
           end;
           Post = function()
                 popScope()
           end;
      }
      visitor.FunctionStat = {
            Pre = function(stat)
                  -- Function stat adds a new scope containing the function
arguments
                  -- as local variables.
                  -- A function stat may also assign to a global variable if it is
in
                  -- the form `function foo()` with no additional dots/colons in
the
                  -- name chain.
                  local nameChain = stat.NameChain
                  local var;
                  if #nameChain == 1 then
                        -- If there is only one item in the name chain, then the
first item
                        -- is a reference to a global variable.
                        var = addGlobalReference(nameChain[1].Source,
function(name)
                              nameChain[1].Source = name
                        end)
                  else
                        var = referenceVariable(nameChain[1].Source, function(name)
                              nameChain[1].Source = name
                        end)
                  end
                  var.AssignedTo = true
                  pushScope()
                  for index, ident in pairs(stat.ArgList) do
                        addLocalVar(ident.Source, function(name)
                              ident.Source = name
                        end, {
                              Type = 'Argument';
                              Index = index;
                        })
                  end
            end;
            Post = function()
                  popScope()
            end;
      }
      visitor.GenericForStat = {
            Pre = function(stat)
           -- Generic fors need an extra scope holding the range variables
           -- Need a custom visitor so that the generator expressions can be
           -- visited before we push a scope, but the body can be visited
           -- after we push a scope.
           for _, ex in pairs(stat.GeneratorList) do
                 VisitAst(ex, visitor)
           end
           pushScope()
           for index, ident in pairs(stat.VarList) do
                 addLocalVar(ident.Source, function(name)
                       ident.Source = name
                 end, {
                       Type = 'ForRange';
                       Index = index;
                 })
           end
           VisitAst(stat.Body, visitor)
           popScope()
           return true -- Custom visit
      end;
}
visitor.NumericForStat = {
      Pre = function(stat)
            -- Numeric fors need an extra scope holding the range variables
            -- Need a custom visitor so that the generator expressions can be
            -- visited before we push a scope, but the body can be visited
            -- after we push a scope.
            for _, ex in pairs(stat.RangeList) do
                  VisitAst(ex, visitor)
            end
            pushScope()
            for index, ident in pairs(stat.VarList) do
                  addLocalVar(ident.Source, function(name)
                        ident.Source = name
                  end, {
                        Type = 'ForRange';
                        Index = index;
                  })
            end
            VisitAst(stat.Body, visitor)
            popScope()
            return true -- Custom visit
      end;
}
visitor.AssignmentStat = {
      Post = function(stat)
            -- For an assignment statement we need to mark the
            -- "assigned to" flag on variables.
            for _, ex in pairs(stat.Lhs) do
                  if ex.Variable then
                        ex.Variable.AssignedTo = true
                  end
            end
      end;
}
VisitAst(ast, visitor)
      printExpr = function(expr)
            if expr.Type == 'BinopExpr' then
                  printExpr(expr.Lhs)
                  printt(expr.Token_Op)
                  printExpr(expr.Rhs)
            elseif expr.Type == 'UnopExpr' then
                  printt(expr.Token_Op)
                  printExpr(expr.Rhs)
            elseif expr.Type == 'NumberLiteral' or expr.Type == 'StringLiteral' or
                  expr.Type == 'NilLiteral' or expr.Type == 'BooleanLiteral' or
                  expr.Type == 'VargLiteral'
            then
                  -- Just print the token
                  printt(expr.Token)
            elseif expr.Type == 'FieldExpr' then
                  printExpr(expr.Base)
                  printt(expr.Token_Dot)
                  printt(expr.Field)
            elseif expr.Type == 'IndexExpr' then
                  printExpr(expr.Base)
                  printt(expr.Token_OpenBracket)
                  printExpr(expr.Index)
                  printt(expr.Token_CloseBracket)
            elseif expr.Type == 'MethodExpr' or expr.Type == 'CallExpr' then
                  printExpr(expr.Base)
                  if expr.Type == 'MethodExpr' then
                        printt(expr.Token_Colon)
                        printt(expr.Method)
                  end
                  if expr.FunctionArguments.CallType == 'StringCall' then
                        printt(expr.FunctionArguments.Token)
                  elseif expr.FunctionArguments.CallType == 'ArgCall' then
                        printt(expr.FunctionArguments.Token_OpenParen)
                        for index, argExpr in pairs(expr.FunctionArguments.ArgList)
do
                              printExpr(argExpr)
                              local sep =
expr.FunctionArguments.Token_CommaList[index]
                              if sep then
                                    printt(sep)
                              end
                        end
                        printt(expr.FunctionArguments.Token_CloseParen)
                  elseif expr.FunctionArguments.CallType == 'TableCall' then
                        printExpr(expr.FunctionArguments.TableExpr)
                  end
            elseif expr.Type == 'FunctionLiteral' then
                  printt(expr.Token_Function)
                  printt(expr.Token_OpenParen)
                  for index, arg in pairs(expr.ArgList) do
                        printt(arg)
                        local comma = expr.Token_ArgCommaList[index]
                        if comma then
                              printt(comma)
                        end
                  end
                  printt(expr.Token_CloseParen)
                  printStat(expr.Body)
                  printt(expr.Token_End)
            elseif expr.Type == 'VariableExpr' then
                  printt(expr.Token)
            elseif expr.Type == 'ParenExpr' then
                  printt(expr.Token_OpenParen)
                  printExpr(expr.Expression)
                  printt(expr.Token_CloseParen)
            elseif expr.Type == 'TableLiteral' then
                  printt(expr.Token_OpenBrace)
                  for index, entry in pairs(expr.EntryList) do
                        if entry.EntryType == 'Field' then
                              printt(entry.Field)
                              printt(entry.Token_Equals)
                              printExpr(entry.Value)
                        elseif entry.EntryType == 'Index' then
                              printt(entry.Token_OpenBracket)
                              printExpr(entry.Index)
                              printt(entry.Token_CloseBracket)
                              printt(entry.Token_Equals)
                              printExpr(entry.Value)
                        elseif entry.EntryType == 'Value' then
                              printExpr(entry.Value)
                        else
                              assert(false, "unreachable")
                        end
                        local sep = expr.Token_SeparatorList[index]
                        if sep then
                              printt(sep)
                        end
                  end
                  printt(expr.Token_CloseBrace)
            else
                  assert(false, "unreachable, type:
"..expr.Type..":"..FormatTable(expr))
            end
      end
     printStat = function(stat)
           if stat.Type == 'StatList' then
                 for index, ch in pairs(stat.StatementList) do
                       printStat(ch)
                       if stat.SemicolonList[index] then
                             printt(stat.SemicolonList[index])
                       end
                 end
elseif stat.Type == 'BreakStat' then
      printt(stat.Token_Break)
elseif stat.Type == 'ReturnStat' then
      printt(stat.Token_Return)
      for index, expr in pairs(stat.ExprList) do
            printExpr(expr)
            if stat.Token_CommaList[index] then
                  printt(stat.Token_CommaList[index])
            end
      end
elseif stat.Type == 'LocalVarStat' then
      printt(stat.Token_Local)
      for index, var in pairs(stat.VarList) do
            printt(var)
            local comma = stat.Token_VarCommaList[index]
            if comma then
                  printt(comma)
            end
      end
      if stat.Token_Equals then
            printt(stat.Token_Equals)
            for index, expr in pairs(stat.ExprList) do
                  printExpr(expr)
                  local comma = stat.Token_ExprCommaList[index]
                  if comma then
                        printt(comma)
                  end
            end
      end
elseif stat.Type == 'LocalFunctionStat' then
      printt(stat.Token_Local)
      printt(stat.FunctionStat.Token_Function)
      printt(stat.FunctionStat.NameChain[1])
      printt(stat.FunctionStat.Token_OpenParen)
      for index, arg in pairs(stat.FunctionStat.ArgList) do
            printt(arg)
            local comma = stat.FunctionStat.Token_ArgCommaList[index]
            if comma then
                  printt(comma)
            end
      end
      printt(stat.FunctionStat.Token_CloseParen)
      printStat(stat.FunctionStat.Body)
      printt(stat.FunctionStat.Token_End)
elseif stat.Type == 'FunctionStat' then
      printt(stat.Token_Function)
      for index, part in pairs(stat.NameChain) do
            printt(part)
            local sep = stat.Token_NameChainSeparator[index]
            if sep then
                  printt(sep)
            end
      end
      printt(stat.Token_OpenParen)
      for index, arg in pairs(stat.ArgList) do
            printt(arg)
            local comma = stat.Token_ArgCommaList[index]
            if comma then
                  printt(comma)
            end
      end
      printt(stat.Token_CloseParen)
      printStat(stat.Body)
      printt(stat.Token_End)
elseif stat.Type == 'RepeatStat' then
      printt(stat.Token_Repeat)
      printStat(stat.Body)
      printt(stat.Token_Until)
      printExpr(stat.Condition)
elseif stat.Type == 'GenericForStat' then
      printt(stat.Token_For)
      for index, var in pairs(stat.VarList) do
            printt(var)
            local sep = stat.Token_VarCommaList[index]
            if sep then
                  printt(sep)
            end
      end
      printt(stat.Token_In)
      for index, expr in pairs(stat.GeneratorList) do
            printExpr(expr)
            local sep = stat.Token_GeneratorCommaList[index]
            if sep then
                  printt(sep)
            end
      end
      printt(stat.Token_Do)
      printStat(stat.Body)
      printt(stat.Token_End)
elseif stat.Type == 'NumericForStat' then
      printt(stat.Token_For)
      for index, var in pairs(stat.VarList) do
            printt(var)
            local sep = stat.Token_VarCommaList[index]
            if sep then
                  printt(sep)
            end
      end
      printt(stat.Token_Equals)
      for index, expr in pairs(stat.RangeList) do
            printExpr(expr)
            local sep = stat.Token_RangeCommaList[index]
            if sep then
                  printt(sep)
            end
      end
      printt(stat.Token_Do)
      printStat(stat.Body)
      printt(stat.Token_End)
elseif stat.Type == 'WhileStat' then
      printt(stat.Token_While)
      printExpr(stat.Condition)
      printt(stat.Token_Do)
      printStat(stat.Body)
      printt(stat.Token_End)
elseif stat.Type == 'DoStat' then
      printt(stat.Token_Do)
      printStat(stat.Body)
                  printt(stat.Token_End)
            elseif stat.Type == 'IfStat' then
                  printt(stat.Token_If)
                  printExpr(stat.Condition)
                  printt(stat.Token_Then)
                  printStat(stat.Body)
                  for _, clause in pairs(stat.ElseClauseList) do
                        printt(clause.Token)
                        if clause.Condition then
                              printExpr(clause.Condition)
                              printt(clause.Token_Then)
                        end
                        printStat(clause.Body)
                  end
                  printt(stat.Token_End)
            elseif stat.Type == 'CallExprStat' then
                  printExpr(stat.Expression)
            elseif stat.Type == 'AssignmentStat' then
                  for index, ex in pairs(stat.Lhs) do
                        printExpr(ex)
                        local sep = stat.Token_LhsSeparatorList[index]
                        if sep then
                              printt(sep)
                        end
                  end
                  printt(stat.Token_Equals)
                  for index, ex in pairs(stat.Rhs) do
                        printExpr(ex)
                        local sep = stat.Token_RhsSeparatorList[index]
                        if sep then
                              printt(sep)
                        end
                  end
            else
                  assert(false, "unreachable")
            end
      end
      printStat(ast)
end
local currentIndent = 0
formatExpr = function(expr)
      if expr.Type == 'BinopExpr' then
            formatExpr(expr.Lhs)
            formatExpr(expr.Rhs)
            if expr.Token_Op.Source == '..' then
                  -- No padding on ..
            else
                  padExpr(expr.Rhs)
                  padToken(expr.Token_Op)
            end
      elseif expr.Type == 'UnopExpr' then
            formatExpr(expr.Rhs)
            --(expr.Token_Op)
      elseif expr.Type == 'NumberLiteral' or expr.Type == 'StringLiteral' or
            expr.Type == 'NilLiteral' or expr.Type == 'BooleanLiteral' or
            expr.Type == 'VargLiteral'
      then
            -- Nothing to do
            --(expr.Token)
      elseif expr.Type == 'FieldExpr' then
            formatExpr(expr.Base)
            --(expr.Token_Dot)
            --(expr.Field)
      elseif expr.Type == 'IndexExpr' then
            formatExpr(expr.Base)
            formatExpr(expr.Index)
                 --(expr.Token_OpenBracket)
                 --(expr.Token_CloseBracket)
           elseif expr.Type == 'MethodExpr' or expr.Type == 'CallExpr' then
                 formatExpr(expr.Base)
                 if expr.Type == 'MethodExpr' then
                       --(expr.Token_Colon)
                       --(expr.Method)
                 end
                 if expr.FunctionArguments.CallType == 'StringCall' then
                       --(expr.FunctionArguments.Token)
                 elseif expr.FunctionArguments.CallType == 'ArgCall' then
                       --(expr.FunctionArguments.Token_OpenParen)
                       for index, argExpr in pairs(expr.FunctionArguments.ArgList)
do
                              formatExpr(argExpr)
                              if index > 1 then
                                    padExpr(argExpr)
                              end
                              local sep =
expr.FunctionArguments.Token_CommaList[index]
                              if sep then
                                    --(sep)
                              end
                        end
                        --(expr.FunctionArguments.Token_CloseParen)
                  elseif expr.FunctionArguments.CallType == 'TableCall' then
                        formatExpr(expr.FunctionArguments.TableExpr)
                  end
            elseif expr.Type == 'FunctionLiteral' then
                  --(expr.Token_Function)
                  --(expr.Token_OpenParen)
                  for index, arg in pairs(expr.ArgList) do
                        --(arg)
                        if index > 1 then
                              padToken(arg)
                        end
                        local comma = expr.Token_ArgCommaList[index]
                        if comma then
                              --(comma)
                        end
                  end
                  --(expr.Token_CloseParen)
                  formatBody(expr.Token_CloseParen, expr.Body, expr.Token_End)
            elseif expr.Type == 'VariableExpr' then
                  --(expr.Token)
            elseif expr.Type == 'ParenExpr' then
                  formatExpr(expr.Expression)
                  --(expr.Token_OpenParen)
                  --(expr.Token_CloseParen)
            elseif expr.Type == 'TableLiteral' then
                  --(expr.Token_OpenBrace)
                  if #expr.EntryList == 0 then
                        -- Nothing to do
                  else
                        indent()
                        for index, entry in pairs(expr.EntryList) do
                              if entry.EntryType == 'Field' then
                                    applyIndent(entry.Field)
                                    padToken(entry.Token_Equals)
                                   formatExpr(entry.Value)
                                   padExpr(entry.Value)
                             elseif entry.EntryType == 'Index' then
                                   applyIndent(entry.Token_OpenBracket)
                                   formatExpr(entry.Index)
                                   --(entry.Token_CloseBracket)
                                   padToken(entry.Token_Equals)
                                   formatExpr(entry.Value)
                                   padExpr(entry.Value)
                             elseif entry.EntryType == 'Value' then
                                   formatExpr(entry.Value)
                                   applyIndent(entry.Value:GetFirstToken())
                             else
                                   assert(false, "unreachable")
                             end
                             local sep = expr.Token_SeparatorList[index]
                             if sep then
                                   --(sep)
                             end
                       end
                       undent()
                       applyIndent(expr.Token_CloseBrace)
                  end
                  --(expr.Token_CloseBrace)
           else
                  assert(false, "unreachable, type:
"..expr.Type..":"..FormatTable(expr))
            end
      end
     formatStat = function(stat)
           if stat.Type == 'StatList' then
                 for _, stat in pairs(stat.StatementList) do
                       formatStat(stat)
                       applyIndent(stat:GetFirstToken())
                 end
      formatStat(ast)
end
            -- Cases to consider:
            --    Touching minus signs -> comment: `- -42` -> `--42' is invalid
            --    Touching words: `a b` -> `ab` is invalid
            --    Touching digits: `2 3`, can't occurr in the Lua syntax as number
literals aren't   a primary expression
            --    Abiguous syntax: `f(x)\n(x)()` is already disallowed, we can't
cause a problem   by removing newlines
      stripExpr = function(expr)
            if expr.Type == 'BinopExpr' then
                  stripExpr(expr.Lhs)
                  stript(expr.Token_Op)
                  stripExpr(expr.Rhs)
                  -- Handle the `a - -b` -/-> `a--b` case which would otherwise
incorrectly generate a comment
                  -- Also handles operators "or" / "and" which definitely need
joining logic in a bunch of cases
                  joint(expr.Token_Op, expr.Rhs:GetFirstToken())
                  joint(expr.Lhs:GetLastToken(), expr.Token_Op)
            elseif expr.Type == 'UnopExpr' then
                  stript(expr.Token_Op)
                  stripExpr(expr.Rhs)
                  -- Handle the `- -b` -/-> `--b` case which would otherwise
incorrectly generate a comment
                  joint(expr.Token_Op, expr.Rhs:GetFirstToken())
            elseif expr.Type == 'NumberLiteral' or expr.Type == 'StringLiteral' or
                  expr.Type == 'NilLiteral' or expr.Type == 'BooleanLiteral' or
                  expr.Type == 'VargLiteral'
            then
                  -- Just print the token
                  stript(expr.Token)
            elseif expr.Type == 'FieldExpr' then
                  stripExpr(expr.Base)
                 stript(expr.Token_Dot)
                 stript(expr.Field)
           elseif expr.Type == 'IndexExpr' then
                 stripExpr(expr.Base)
                 stript(expr.Token_OpenBracket)
                 stripExpr(expr.Index)
                 stript(expr.Token_CloseBracket)
           elseif expr.Type == 'MethodExpr' or expr.Type == 'CallExpr' then
                 stripExpr(expr.Base)
                 if expr.Type == 'MethodExpr' then
                       stript(expr.Token_Colon)
                       stript(expr.Method)
                 end
                 if expr.FunctionArguments.CallType == 'StringCall' then
                       stript(expr.FunctionArguments.Token)
                 elseif expr.FunctionArguments.CallType == 'ArgCall' then
                       stript(expr.FunctionArguments.Token_OpenParen)
                       for index, argExpr in pairs(expr.FunctionArguments.ArgList)
do
                              stripExpr(argExpr)
                              local sep =
expr.FunctionArguments.Token_CommaList[index]
                              if sep then
                                    stript(sep)
                              end
                        end
                        stript(expr.FunctionArguments.Token_CloseParen)
                  elseif expr.FunctionArguments.CallType == 'TableCall' then
                        stripExpr(expr.FunctionArguments.TableExpr)
                  end
            elseif expr.Type == 'FunctionLiteral' then
                  stript(expr.Token_Function)
                  stript(expr.Token_OpenParen)
                  for index, arg in pairs(expr.ArgList) do
                        stript(arg)
                        local comma = expr.Token_ArgCommaList[index]
                        if comma then
                              stript(comma)
                        end
                  end
                  stript(expr.Token_CloseParen)
                  bodyjoint(expr.Token_CloseParen, expr.Body, expr.Token_End)
            elseif expr.Type == 'VariableExpr' then
                  stript(expr.Token)
            elseif expr.Type == 'ParenExpr' then
                  stript(expr.Token_OpenParen)
                  stripExpr(expr.Expression)
                  stript(expr.Token_CloseParen)
            elseif expr.Type == 'TableLiteral' then
                  stript(expr.Token_OpenBrace)
                  for index, entry in pairs(expr.EntryList) do
                        if entry.EntryType == 'Field' then
                              stript(entry.Field)
                              stript(entry.Token_Equals)
                              stripExpr(entry.Value)
                        elseif entry.EntryType == 'Index' then
                              stript(entry.Token_OpenBracket)
                              stripExpr(entry.Index)
                              stript(entry.Token_CloseBracket)
                                stript(entry.Token_Equals)
                                stripExpr(entry.Value)
                          elseif entry.EntryType == 'Value' then
                                stripExpr(entry.Value)
                          else
                                assert(false, "unreachable")
                          end
                          local sep = expr.Token_SeparatorList[index]
                          if sep then
                                stript(sep)
                          end
                  end
                  stript(expr.Token_CloseBrace)
           else
                  assert(false, "unreachable, type:
"..expr.Type..":"..FormatTable(expr))
            end
      end
      stripStat = function(stat)
            if stat.Type == 'StatList' then
                  -- Strip all surrounding whitespace on statement lists along with
separating whitespace
                  for i = 1, #stat.StatementList do
                        local chStat = stat.StatementList[i]
      stripStat(ast)
end
local idGen = 0
local VarDigits = {}
for i = ('a'):byte(), ('z'):byte() do table.insert(VarDigits, string.char(i)) end
for i = ('A'):byte(), ('Z'):byte() do table.insert(VarDigits, string.char(i)) end
for i = ('0'):byte(), ('9'):byte() do table.insert(VarDigits, string.char(i)) end
table.insert(VarDigits, '_')
local VarStartDigits = {}
for i = ('a'):byte(), ('z'):byte() do table.insert(VarStartDigits, string.char(i))
end
for i = ('A'):byte(), ('Z'):byte() do table.insert(VarStartDigits, string.char(i))
end
local function indexToVarName(index)
      local id = ''
      local d = index % #VarStartDigits
      index = (index - d) / #VarStartDigits
      id = id..VarStartDigits[d+1]
      while index > 0 do
            local d = index % #VarDigits
            index = (index - d) / #VarDigits
            id = id..VarDigits[d+1]
      end
      return id
end
local function genNextVarName()
      local varToUse = idGen
      idGen = idGen + 1
      return indexToVarName(varToUse)
end
local function genVarName()
      local varName = ''
      repeat
            varName = genNextVarName()
     until not Keywords[varName]
     return varName
end
local function MinifyVariables(globalScope, rootScope)
      -- externalGlobals is a set of global variables that have not been assigned
to, that is
      -- global variables defined "externally to the script". We are not going to
be renaming
      -- those, and we have to make sure that we don't collide with them when
renaming
      -- things so we keep track of them in this set.
      local externalGlobals = {}
            if var.Scope then
                  -- Now we need to mark the name as unusable by any variables:
                  -- 1) At the same depth that overlap lifetime with this one
                  -- 2) At a deeper level, which have a reference to this variable
in their lifetimes
                  -- 3) At a shallower level, which are referenced during this
variable's lifetime
                  for _, otherVar in pairs(allVariables) do
                        if not otherVar.Renamed then
                              if not otherVar.Scope or otherVar.Scope.Depth <
var.Scope.Depth then
                                    -- Check Global variable (Which is always at a
shallower level)
                                    -- or
                                    -- Check case 3
                                    -- The other var is at a shallower depth, is
there a reference to it
                                    -- durring this variable's lifetime?
                                    for _, refAt in
pairs(otherVar.ReferenceLocationList) do
                                          if refAt >= var.BeginLocation and refAt
<= var.ScopeEndLocation then
                                                -- Collide
                                                  otherVar.UsedNameArray[i] = true
                                                  break
                                            end
                                      end
      -- --
      -- print("Total Variables: "..#allVariables)
      -- print("Total Range:
"..rootScope.BeginLocation.."-"..rootScope.EndLocation)
      -- print("")
      -- for _, var in pairs(allVariables) do
      --    io.write("`"..var.Name.."':\n\t#symbols: "..#var.RenameList..
      --          "\n\tassigned to: "..tostring(var.AssignedTo))
      --    if var.Type == 'Local' then
      --          io.write("\n\trange: "..var.BeginLocation.."-"..var.EndLocation)
      --          io.write("\n\tlocal type: "..var.Info.Type)
      --    end
      --    io.write("\n\n")
      -- end
-- For each variable, we need to build a list of names that collide with it
      --
      --error()
end
      local localNumber = 1
      local globalNumber = 1