-- A control flow graph with "lifted" expressions

-- HLL Nodes:
-- node := assign({r, e[e]}, e)
--       | jcond({== | e}, l_fallthrough, l_jump)
--       | jmp(l)
--       | return(e)
--       | foreach(r*, e, l_fallthrough, l_jump)
--       | fori (r, e, e, e, l_fallthrough, l_jump)

-- expr := r
--       | const
--       | up
--       | e[e]
--       | {e*}
--       | e(e*)
--       | e:string(e*)
--       | e (+ | - | * | / | % | ^ | ..) e
--       | (- | not | #) e
--       | e (==, <=, <, ...) e
--       | ...

-- concretization:
-- {kind = "assign", type = "node", args...}

-- Translation is syntax directed, and then we can start merging based on liveness analysis

local liveness = require 'luainlua.cfg.liveness'
local inlineable = require 'luainlua.hll.inlineable'
local undump = require 'luainlua.bytecode.undump'
local cfg = require 'luainlua.cfg.cfg'
local utils = require 'luainlua.common.utils'

local hll = {}

local function used_variables(closure, pc)
  local instr = closure.code[pc]
  return liveness.uses[instr.op](nil, pc, instr, {})
end

-- target language: hll
function hll.assign(left, right) end

function hll.jcond() end

function hll.jmp() end

function hll.ret() end

function hll.foreach() end

function hll.fori() end

-- target language: expr

local function translate(g, closure)
  -- simple syntax directed translation into hll
end

local closure = undump.undump(function(x, y) return {x, y} end)

local g = cfg.make(closure)

print(cfg.tostring(g))

local liveness_fixedpoint = liveness.solve(g, closure)
local solution = inlineable.solve(g, closure, liveness_fixedpoint)

for pc, instr in ipairs(closure.code) do
  local uses = used_variables(closure, pc)
  local inlineables = {}
  for variable in pairs(uses) do
    if solution:is_inlineable_at(pc, variable) then
      inlineables[variable] = true
    end
  end
  print(pc, instr, utils.to_list(inlineables))
end

return hll