blob: 7875874bcc5b2a99768e761c5ad90f47e7b0fcee [file] [log] [blame]
-------------------------------------------------------------------------------
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
--
-- All rights reserved.
--
-- This program and the accompanying materials are made available
-- under the terms of the Eclipse Public License v1.0 which
-- accompanies this distribution, and is available at
-- http://www.eclipse.org/legal/epl-v10.html
--
-- This program and the accompanying materials are also made available
-- under the terms of the MIT public license which accompanies this
-- distribution, and is available at http://www.lua.org/license.html
--
-- Contributors:
-- Fabien Fleutot - API and implementation
--
-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Execute an `mlc.*_to_ast()' in a separate lua process.
-- Communication between processes goes through temporary files,
-- for the sake of portability.
--------------------------------------------------------------------------------
mlc_xcall = { }
--------------------------------------------------------------------------------
-- Number of lines to remove at the end of a traceback, should it be
-- dumped due to a compilation error in metabugs mode.
--------------------------------------------------------------------------------
local STACK_LINES_TO_CUT = 7
--------------------------------------------------------------------------------
-- (Not intended to be called directly by users)
--
-- This is the back-end function, called in a separate lua process
-- by `mlc_xcall.client_*()' through `os.execute()'.
-- * inputs:
-- * the name of a lua source file to compile in a separate process
-- * the name of a writable file where the resulting ast is dumped
-- with `serialize()'.
-- * metabugs: if true and an error occurs during compilation,
-- the compiler's stacktrace is printed, allowing meta-programs
-- debugging.
-- * results:
-- * an exit status of 0 or -1, depending on whethet compilation
-- succeeded;
-- * the ast file filled will either the serialized ast, or the
-- error message.
--------------------------------------------------------------------------------
function mlc_xcall.server (luafilename, astfilename, metabugs)
-- We don't want these to be loaded when people only do client-side business
require 'metalua.compiler'
require 'serialize'
mlc.metabugs = metabugs
-- compile the content of luafile name in an AST, serialized in astfilename
--local status, ast = pcall (mlc.luafile_to_ast, luafilename)
local status, ast
local function compile() return mlc.luafile_to_ast (luafilename) end
if mlc.metabugs then
--print 'mlc_xcall.server/metabugs'
--status, ast = xpcall (compile, debug.traceback)
--status, ast = xpcall (compile, debug.traceback)
local function tb(msg)
local r = debug.traceback(msg)
-- Cut superfluous end lines
local line_re = '\n[^\n]*'
local re = "^(.-)" .. (line_re) :rep (STACK_LINES_TO_CUT) .. "$"
return r :strmatch (re) or r
end
--status, ast = xpcall (compile, debug.traceback)
status, ast = xpcall (compile, tb)
else status, ast = pcall (compile) end
if status then
local check_status, check_msg = pcall (mlc.check_ast, 'block', ast)
if not check_status then status, ast = false, check_msg end
end
local out = io.open (astfilename, 'w')
if status then -- success
out:write (serialize (ast))
out:close ()
os.exit (0)
else -- failure, `ast' is actually the error message
out:write (ast)
out:close ()
os.exit (-1)
end
end
--------------------------------------------------------------------------------
-- Compile the file whose name is passed as argument, in a separate process,
-- communicating through a temporary file.
-- returns:
-- * true or false, indicating whether the compilation succeeded
-- * the ast, or the error message.
--------------------------------------------------------------------------------
function mlc_xcall.client_file (luafile)
-- printf("\n\nmlc_xcall.client_file(%q)\n\n", luafile)
local tmpfilename = os.tmpname()
local cmd = string.format (
[=[lua -l metalua.mlc_xcall -e "mlc_xcall.server([[%s]], [[%s]], %s)"]=],
luafile, tmpfilename, mlc.metabugs and "true" or "false")
-- printf("os.execute [[%s]]\n\n", cmd)
local status = (0 == os.execute (cmd))
local result -- ast or error msg
if status then
result = (lua_loadfile or loadfile) (tmpfilename) ()
else
local f = io.open (tmpfilename)
result = f :read '*a'
f :close()
end
os.remove(tmpfilename)
return status, result
end
--------------------------------------------------------------------------------
-- Compile a source string into an ast, by dumping it in a tmp
-- file then calling `mlc_xcall.client_file()'.
-- returns: the same as `mlc_xcall.client_file()'.
--------------------------------------------------------------------------------
function mlc_xcall.client_literal (luasrc)
local srcfilename = os.tmpname()
local srcfile, msg = io.open (srcfilename, 'w')
if not srcfile then print(msg) end
srcfile :write (luasrc)
srcfile :close ()
local status, ast = mlc_xcall.client_file (srcfilename)
os.remove(srcfilename)
return status, ast
end
return mlc_xcall