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}