1 --------------------------------------------------------------------------------
2 -- Execute an `mlc.ast_of_*()' in a separate lua process.
3 -- Communication between processes goes through temporary files,
4 -- for the sake of portability.
5 --------------------------------------------------------------------------------
9 --------------------------------------------------------------------------------
10 -- Number of lines to remove at the end of a traceback, should it be
11 -- dumped due to a compilation error in metabugs mode.
12 --------------------------------------------------------------------------------
13 local STACK_LINES_TO_CUT = 7
15 --------------------------------------------------------------------------------
16 -- (Not intended to be called directly by users)
18 -- This is the back-end function, called in a separate lua process
19 -- by `mlc_xcall.client_*()' through `os.execute()'.
21 -- * the name of a lua source file to compile in a separate process
22 -- * the name of a writable file where the resulting ast is dumped
23 -- with `serialize()'.
24 -- * metabugs: if true and an error occurs during compilation,
25 -- the compiler's stacktrace is printed, allowing meta-programs
28 -- * an exit status of 0 or -1, depending on whethet compilation
30 -- * the ast file filled will either the serialized ast, or the
32 --------------------------------------------------------------------------------
33 function mlc_xcall.server (luafilename, astfilename, metabugs)
35 -- We don't want these to be loaded when people only do client-side business
36 require 'metalua.compiler'
39 mlc.metabugs = metabugs
41 -- compile the content of luafile name in an AST, serialized in astfilename
42 --local status, ast = pcall (mlc.luafile_to_ast, luafilename)
44 local function compile() return mlc.luafile_to_ast (luafilename) end
46 print 'mlc_xcall.server/metabugs'
47 --status, ast = xpcall (compile, debug.traceback)
48 --status, ast = xpcall (compile, debug.traceback)
49 local function tb(msg)
50 local r = debug.traceback(msg)
52 -- Cut superfluous end lines
53 local line_re = '\n[^\n]*'
54 local re = "^(.-)" .. (line_re) :rep (STACK_LINES_TO_CUT) .. "$"
55 return r :strmatch (re) or r
57 --status, ast = xpcall (compile, debug.traceback)
58 status, ast = xpcall (compile, tb)
59 else status, ast = pcall (compile) end
60 local out = io.open (astfilename, 'w')
61 if status then -- success
62 out:write (serialize (ast))
65 else -- failure, `ast' is actually the error message
72 --------------------------------------------------------------------------------
73 -- Compile the file whose name is passed as argument, in a separate process,
74 -- communicating through a temporary file.
76 -- * true or false, indicating whether the compilation succeeded
77 -- * the ast, or the error message.
78 --------------------------------------------------------------------------------
79 function mlc_xcall.client_file (luafile)
81 -- printf("\n\nmlc_xcall.client_file(%q)\n\n", luafile)
83 local tmpfilename = os.tmpname()
84 local cmd = string.format (
85 [=[lua -l metalua.mlc_xcall -e "mlc_xcall.server([[%s]], [[%s]], %s)"]=],
86 luafile, tmpfilename, mlc.metabugs and "true" or "false")
88 -- printf("os.execute [[%s]]\n\n", cmd)
90 local status = (0 == os.execute (cmd))
91 local result -- ast or error msg
93 result = (lua_loadfile or loadfile) (tmpfilename) ()
95 local f = io.open (tmpfilename)
99 os.remove(tmpfilename)
100 return status, result
103 --------------------------------------------------------------------------------
104 -- Compile a source string into an ast, by dumping it in a tmp
105 -- file then calling `mlc_xcall.client_file()'.
106 -- returns: the same as `mlc_xcall.client_file()'.
107 --------------------------------------------------------------------------------
108 function mlc_xcall.client_literal (luasrc)
109 local srcfilename = os.tmpname()
110 local srcfile, msg = io.open (srcfilename, 'w')
111 if not srcfile then print(msg) end
112 srcfile :write (luasrc)
114 local status, ast = mlc_xcall.client_file (srcfilename)
115 os.remove(srcfilename)