local lex_setup = require('lang.lexer')
local parse = require('lang.parser')
local lua_ast = require('lang.lua_ast')
local reader = require('lang.reader')

-- Two kind of backend can be used to generate the code from the AST:
-- - "generator", generates LuaJIT bytecode
-- - "luacode_generator", generates Lua code
--
-- Both can be used interchangeably, they take the AST tree and produce
-- a string that can be passed to the function "loadstring".
-- In the case of the bytecode generator the string will be actually a
-- binary blob that corresponds to the generated bytecode.


local function lang_toolkit_error(msg)
   if string.sub(msg, 1, 9) == "LLT-ERROR" then
        return false, "luajit-lang-toolkit: " .. string.sub(msg, 10)
    else
        error(msg)
    end
end

local function compile(reader, filename, options)
    local generator
    if options and options.code then
        generator = require('lang.luacode_generator')
    else
        generator = require('lang.generator')
    end
    local ls = lex_setup(reader, filename)
    local ast_builder = lua_ast.New()
    local parse_success, ast_tree = pcall(parse, ast_builder, ls)
    if not parse_success then
        return lang_toolkit_error(ast_tree)
    end
    local success, luacode = pcall(generator, ast_tree, filename)
    if not success then
        return lang_toolkit_error(luacode)
    end
    return true, luacode
end

local function lang_loadstring(src, filename, options)
    return compile(reader.string(src), filename or "stdin", options)
end

local function lang_loadfile(filename, options)
    return compile(reader.file(filename), filename or "stdin", options)
end

return { string = lang_loadstring, file = lang_loadfile }
