]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/mlc_xcall.lua
fixed metabug mode
[metalua.git] / src / lib / metalua / mlc_xcall.lua
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 --------------------------------------------------------------------------------
6
7 mlc_xcall = { }
8
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
14
15 --------------------------------------------------------------------------------
16 -- (Not intended to be called directly by users)
17 --
18 -- This is the back-end function, called in a separate lua process
19 -- by `mlc_xcall.client_*()' through `os.execute()'.
20 --  * inputs:
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
26 --       debugging.
27 --  * results:
28 --     * an exit status of 0 or -1, depending on whethet compilation
29 --       succeeded;
30 --     * the ast file filled will either the serialized ast, or the
31 --       error message.
32 --------------------------------------------------------------------------------
33 function mlc_xcall.server (luafilename, astfilename, metabugs)
34
35    -- We don't want these to be loaded when people only do client-side business
36    require 'metalua.compiler'
37    require 'serialize'
38
39    mlc.metabugs = metabugs
40
41    -- compile the content of luafile name in an AST, serialized in astfilename
42    --local status, ast = pcall (mlc.luafile_to_ast, luafilename)
43    local status, ast
44    local function compile() return mlc.luafile_to_ast (luafilename) end
45    if mlc.metabugs then 
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)
51
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
56       end
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))
63       out:close ()
64       os.exit (0)
65    else -- failure, `ast' is actually the error message
66       out:write (ast)
67       out:close ()
68       os.exit (-1)
69    end      
70 end
71
72 --------------------------------------------------------------------------------
73 -- Compile the file whose name is passed as argument, in a separate process,
74 -- communicating through a temporary file.
75 -- returns:
76 --  * true or false, indicating whether the compilation succeeded
77 --  * the ast, or the error message.
78 --------------------------------------------------------------------------------
79 function mlc_xcall.client_file (luafile)
80
81    -- printf("\n\nmlc_xcall.client_file(%q)\n\n", luafile)
82
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")
87
88    -- printf("os.execute [[%s]]\n\n", cmd)
89
90    local status = (0 == os.execute (cmd))
91    local result -- ast or error msg
92    if status then 
93       result = (lua_loadfile or loadfile) (tmpfilename) ()
94    else
95       local f = io.open (tmpfilename)
96       result = f :read '*a'
97       f :close()
98    end
99    os.remove(tmpfilename)
100    return status, result
101 end
102
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)
113    srcfile :close ()
114    local status, ast = mlc_xcall.client_file (srcfilename)
115    os.remove(srcfilename)
116    return status, ast
117 end
118
119 return mlc_xcall