-- Copyright (c) 2020, The Pallene Developers
-- Pallene is licensed under the MIT license.
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

-- !!! IMPORTANT - READ THIS !!!
--
-- If you change the output of this translator, please run the `benchmarks/generate_lua` script
-- to update the ".lua" files of our benchmarks.

----------

-- PALLENE TO LUA TRANSLATOR
-- =========================
-- One of the things Pallene promises is the Gradual Guarantee: the behavior of a Pallene program
-- should be similar to an equivalent Lua program that you would obtain by erasing all the type
-- annotations. To make it easier for us to test this property, this module implements such type
-- erasure algorithm. This alternate backend can be invoked using --emit-lua.
--
-- The generation of Lua is performed by a different backend (implemented here). It accepts input
-- string and the AST generated by the parser. The generator then walks over the AST replacing
-- type annotations with white space. Interestingly spaces, newlines, comments and pretty much
-- everything else other than type annotations are retained in the translated code. Thus, the
-- formatting in the original input is preserved, which means the error messages always point to
-- the same location in both Pallene and Lua code.

local util = require "pallene.util"

local translator = {}

local Translator = util.Class()

function Translator:init(input)
    self.input = input -- string
    self.last_index = 1 -- integer
    self.partials = {} -- list of strings
    return self
end

function Translator:add_previous(stop_index)
    assert(self.last_index <= stop_index + 1)
    local partial = self.input:sub(self.last_index, stop_index)
    table.insert(self.partials, partial)
    self.last_index = stop_index + 1
end

function Translator:erase_region(start_index, stop_index)
    assert(self.last_index <= start_index)
    assert(start_index <= stop_index + 1)
    self:add_previous(start_index - 1)

    local region = self.input:sub(start_index, stop_index)
    local partial = region:gsub("[^\n\r]", "")
    table.insert(self.partials, partial)

    self.last_index = stop_index + 1
end

function translator.translate(input, prog_ast)
    local instance = Translator.new(input)

    -- Erase all type regions
    for _, region in ipairs(prog_ast.type_regions) do
        local start_index = region[1]
        local end_index   = region[2]
        instance:erase_region(start_index, end_index)
    end

    -- Whatever characters that were not included in the partials should be added.
    instance:add_previous(#input)

    return table.concat(instance.partials)
end

return translator
