]> git.lizzy.rs Git - metalua.git/blob - src/compiler/compile.lua
pulled from repo
[metalua.git] / src / compiler / compile.lua
1 ----------------------------------------------------------------------
2 --
3 -- WARNING! You're entering a hackish area, proceed at your own risks!
4 --
5 -- This code partly results from the borrowing, then ruthless abuse, of
6 -- Yueliang's implementation of Lua 5.0 compiler. I claim
7 -- responsibility for all of the ugly, dirty stuff that you might spot
8 -- in it.
9 --
10 -- Eventually, this code will be rewritten, either in Lua or more
11 -- probably in C. Meanwhile, if you're interested into digging
12 -- metalua's sources, this is not the best part to invest your time
13 -- on.
14 --
15 -- End of warning.
16 --
17 ----------------------------------------------------------------------
18
19 ----------------------------------------------------------------------
20 -- Metalua:  $Id: compile.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
21 --
22 -- Summary: Compile ASTs to Lua 5.1 VM function prototype. 
23 -- Largely based on:
24 --
25 -- * Yueliang (http://luaforge.net/projects/yueliang),
26 --   yueliang-0.1.2/orig-5.0.2/lparser.lua
27 --
28 -- * Lua 5.1 sources (http://www.lua.org), src/lparser.c
29 --
30 ----------------------------------------------------------------------
31 --
32 -- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
33 --
34 -- This software is released under the MIT Licence, see licence.txt
35 -- for details.
36 --
37 ----------------------------------------------------------------------
38 -- History:
39 -- $Log: compile.lua,v $
40 -- Revision 1.7  2006/11/15 09:07:50  fab13n
41 -- debugged meta operators.
42 -- Added command line options handling.
43 --
44 -- Revision 1.6  2006/11/10 02:11:17  fab13n
45 -- compiler faithfulness to 5.1 improved
46 -- gg.expr extended
47 -- mlp.expr refactored
48 --
49 -- Revision 1.5  2006/11/09 09:39:57  fab13n
50 -- some cleanup
51 --
52 -- Revision 1.4  2006/11/07 21:29:02  fab13n
53 -- improved quasi-quoting
54 --
55 -- Revision 1.3  2006/11/07 04:37:59  fab13n
56 -- first bootstrapping version.
57 --
58 -- Revision 1.2  2006/11/05 15:08:34  fab13n
59 -- updated code generation, to be compliant with 5.1
60 --
61 ----------------------------------------------------------------------
62
63 module ("bytecode", package.seeall)
64 --require "lopcodes"
65 --require "lcode"
66
67 local debugf = function() end
68 --local debugf=printf
69
70 local stat = { }
71 local expr = { }
72
73 -- GENERAL FIXME: je ne gere pas les parentheses pour empecher l'unpack
74 -- des fonctions dans return et dans table.
75
76 -- GENERAL FIXME: growvector --> checkvector
77
78 MAX_INT            = 2147483645 -- INT_MAX-2 for 32-bit systems (llimits.h)
79 MAXVARS            = 200        -- (llimits.h)
80 MAXUPVALUES        = 32         -- (llimits.h)
81 MAXPARAMS          = 100        -- (llimits.h)
82 LUA_MAXPARSERLEVEL = 200        -- (llimits.h)
83
84 -- from lobject.h
85 VARARG_HASARG   = 1
86 VARARG_ISVARARG = 2
87 VARARG_NEEDSARG = 4
88
89
90 local function hasmultret (k) return k=="VCALL" or k=="VVARARG" end
91
92 -----------------------------------------------------------------------
93 -- Some ASTs take expression lists as children; it should be
94 -- acceptible to give an expression instead, and to automatically
95 -- interpret it as a single element list. That's what does this
96 -- function, adding a surrounding list iff needed.
97 --
98 -- WARNING: "Do" is the tag for chunks, which are essentially lists.
99 -- Therefore, we don't listify stuffs with a "Do" tag.
100 -----------------------------------------------------------------------
101 local function ensure_list (ast)
102    return ast.tag and ast.tag ~= "Do" and {ast} or ast end
103
104 -----------------------------------------------------------------------
105 -- Get a localvar structure { varname, startpc, endpc } from a 
106 -- (zero-based) index of active variable. The catch is: don't get
107 -- confused between local index and active index.
108 --
109 -- locvars[x] contains { varname, startpc, endpc };
110 -- actvar[i] contains the index of the variable in locvars
111 -----------------------------------------------------------------------
112 local function getlocvar (fs, i)
113   return fs.f.locvars[fs.actvar[i]] 
114 end
115
116 local function removevars (fs, tolevel)
117   while fs.nactvar > tolevel do
118      fs.nactvar = fs.nactvar - 1
119      -- There may be dummy locvars due to expr.Stat
120      -- FIXME: strange that they didn't disappear?!
121      local locvar = getlocvar (fs, fs.nactvar)
122      --printf("[REMOVEVARS] removing var #%i = %s", fs.nactvar,
123      --    locvar and tostringv(locvar) or "<nil>")
124      if locvar then locvar.endpc = fs.pc end
125   end
126 end
127
128 -----------------------------------------------------------------------
129 -- [f] has a list of all its local variables, active and inactive.
130 -- Some local vars can correspond to the same register, if they exist
131 -- in different scopes. 
132 -- [fs.nlocvars] is the total number of local variables, not to be
133 -- confused with [fs.nactvar] the numebr of variables active at the
134 -- current PC.
135 -- At this stage, the existence of the variable is not yet aknowledged,
136 -- since [fs.nactvar] and [fs.freereg] aren't updated.
137 -----------------------------------------------------------------------
138 local function registerlocalvar (fs, varname)
139    debugf("[locvar: %s = reg %i]", varname, fs.nlocvars)
140    local f = fs.f
141    f.locvars[fs.nlocvars] = { } -- LocVar
142    f.locvars[fs.nlocvars].varname = varname
143    local nlocvars = fs.nlocvars
144    fs.nlocvars = fs.nlocvars + 1
145    return nlocvars
146 end
147
148 -----------------------------------------------------------------------
149 -- update the active vars counter in [fs] by adding [nvars] of them,
150 -- and sets those variables' [startpc] to the current [fs.pc].
151 -- These variables were allready created, but not yet counted, by
152 -- new_localvar.
153 -----------------------------------------------------------------------
154 local function adjustlocalvars (fs, nvars)
155    --debugf("adjustlocalvars, nvars=%i, previous fs.nactvar=%i,"..
156    --       " #locvars=%i, #actvar=%i", 
157    --       nvars, fs.nactvar, #fs.f.locvars, #fs.actvar)
158
159    fs.nactvar = fs.nactvar + nvars
160    for i = nvars, 1, -1 do
161       --printf ("adjusting actvar #%i", fs.nactvar - i)
162       getlocvar (fs, fs.nactvar - i).startpc = fs.pc
163    end
164 end
165
166 ------------------------------------------------------------------------
167 -- check whether, in an assignment to a local variable, the local variable
168 -- is needed in a previous assignment (to a table). If so, save original
169 -- local value in a safe place and use this safe copy in the previous
170 -- assignment.
171 ------------------------------------------------------------------------
172 local function check_conflict (fs, lh, v)
173   local extra = fs.freereg  -- eventual position to save local variable
174   local conflict = false
175   while lh do
176     if lh.v.k == "VINDEXED" then
177       if lh.v.info == v.info then  -- conflict?
178         conflict = true
179         lh.v.info = extra  -- previous assignment will use safe copy
180       end
181       if lh.v.aux == v.info then  -- conflict?
182         conflict = true
183         lh.v.aux = extra  -- previous assignment will use safe copy
184       end
185     end
186     lh = lh.prev
187   end
188   if conflict then
189     luaK:codeABC (fs, "OP_MOVE", fs.freereg, v.info, 0)  -- make copy
190     luaK:reserveregs (fs, 1)
191   end
192 end
193
194 -----------------------------------------------------------------------
195 -- Create an expdesc. To be updated when expdesc is lua-ified.
196 -----------------------------------------------------------------------
197 local function init_exp (e, k, i)
198   e.f, e.t, e.k, e.info = luaK.NO_JUMP, luaK.NO_JUMP, k, i end
199
200 -----------------------------------------------------------------------
201 -- Reserve the string in tthe constant pool, and return an expdesc
202 -- referring to it.
203 -----------------------------------------------------------------------
204 local function codestring (fs, e, str)
205   --printf( "codestring(%s)", disp.ast(str))
206   init_exp (e, "VK", luaK:stringK (fs, str))
207 end
208
209 -----------------------------------------------------------------------
210 -- search for a local variable named [name] in the function being
211 -- built by [fs]. Doesn't try to visit upvalues.
212 -----------------------------------------------------------------------
213 local function searchvar (fs, name)
214    for i = fs.nactvar - 1, 0, -1 do
215       -- Because of expr.Stat, there can be some actvars which don't
216       -- correspond to any locvar. Hence the checking for locvar's 
217       -- nonnilness before getting the varname.
218       local locvar = getlocvar(fs, i)
219       if locvar and name == locvar.varname then 
220          --printf("Found local var: %s; i = %i", tostringv(locvar), i)
221          return i 
222       end
223    end
224    return -1  -- not found
225 end
226
227 -----------------------------------------------------------------------
228 -- create and return a new proto [f]
229 -----------------------------------------------------------------------
230 local function newproto () 
231   local f = {}
232   f.k = {}
233   f.sizek = 0
234   f.p = {}
235   f.sizep = 0
236   f.code = {}
237   f.sizecode = 0
238   f.sizelineinfo = 0
239   f.sizeupvalues = 0
240   f.nups = 0
241   f.upvalues = {}
242   f.numparams = 0
243   f.is_vararg = 0
244   f.maxstacksize = 0
245   f.lineinfo = {}
246   f.sizelocvars = 0
247   f.locvars = {}
248   f.lineDefined = 0
249   f.source = nil
250   return f
251 end
252
253 ------------------------------------------------------------------------
254 -- create and return a function state [new_fs] as a sub-funcstate of [fs].
255 ------------------------------------------------------------------------
256 local function open_func (old_fs)
257   local new_fs = { }
258   new_fs.upvalues = { }
259   new_fs.actvar = { }
260   local f = newproto ()
261   new_fs.f = f
262   new_fs.prev = old_fs  -- linked list of funcstates
263   new_fs.pc = 0
264   new_fs.lasttarget = -1
265   new_fs.jpc = luaK.NO_JUMP
266   new_fs.freereg = 0
267   new_fs.nk = 0
268   new_fs.h = {}  -- constant table; was luaH_new call
269   new_fs.np = 0
270   new_fs.nlocvars = 0
271   new_fs.nactvar = 0
272   new_fs.bl = nil
273   new_fs.nestlevel =  old_fs and old_fs.nestlevel or 0
274   f.maxstacksize = 2  -- registers 0/1 are always valid
275   new_fs.lastline = 0
276   new_fs.forward_gotos = { }
277   new_fs.labels = { }
278   return new_fs
279 end
280
281 ------------------------------------------------------------------------
282 -- Finish to set up [f] according to final state of [fs]
283 ------------------------------------------------------------------------
284 local function close_func (fs)
285   local f = fs.f
286   --printf("[CLOSE_FUNC] remove any remaining var")
287   removevars (fs, 0)
288   luaK:ret (fs, 0, 0)
289   f.sizecode = fs.pc
290   f.sizelineinfo = fs.pc
291   f.sizek = fs.nk
292   f.sizep = fs.np
293   f.sizelocvars = fs.nlocvars
294   f.sizeupvalues = f.nups
295   assert (fs.bl == nil)
296   if next(fs.forward_gotos) then
297      local x = table.tostring(fs.forward_gotos)
298      error ("Unresolved goto: "..x)
299   end
300 end
301
302 ------------------------------------------------------------------------
303 -- 
304 ------------------------------------------------------------------------
305 local function pushclosure(fs, func, v)
306    local f = fs.f
307    f.p [fs.np] = func.f
308    fs.np = fs.np + 1
309    init_exp (v, "VRELOCABLE", luaK:codeABx (fs, "OP_CLOSURE", 0, fs.np - 1))
310   for i = 0, func.f.nups - 1 do
311     local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
312     luaK:codeABC (fs, o, 0, func.upvalues[i].info, 0)
313   end
314 end
315
316 ------------------------------------------------------------------------
317 -- FIXME: is there a need for f=fs.f? if yes, why not always using it? 
318 ------------------------------------------------------------------------
319 function indexupvalue(fs, name, v)
320    local f = fs.f
321    for i = 0, f.nups - 1 do
322       if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
323          assert(fs.f.upvalues[i] == name)
324          return i
325       end
326    end
327   -- new one
328   f.upvalues[f.nups] = name
329   assert (v.k == "VLOCAL" or v.k == "VUPVAL")
330   fs.upvalues[f.nups] = { k = v.k; info = v.info }
331   local nups = f.nups
332   f.nups = f.nups + 1
333   return nups
334 end
335
336 ------------------------------------------------------------------------
337 --
338 ------------------------------------------------------------------------
339 local function markupval(fs, level)
340   local bl = fs.bl
341   while bl and bl.nactvar > level do bl = bl.previous end
342   if bl then bl.upval = true end
343 end
344
345
346 --for debug only
347 --[[
348 local function bldepth(fs)
349    local i, x= 1, fs.bl
350    while x do i=i+1; x=x.previous end
351    return i
352 end
353 --]]
354
355 ------------------------------------------------------------------------
356 --
357 ------------------------------------------------------------------------
358 local function enterblock (fs, bl, isbreakable)
359   bl.breaklist = luaK.NO_JUMP
360   bl.isbreakable = isbreakable
361   bl.nactvar = fs.nactvar
362   bl.upval = false
363   bl.previous = fs.bl
364   fs.bl = bl
365   assert (fs.freereg == fs.nactvar)
366 end
367
368 ------------------------------------------------------------------------
369 --
370 ------------------------------------------------------------------------
371 local function leaveblock (fs)
372    local bl = fs.bl
373    fs.bl = bl.previous
374    --printf("[LEAVEBLOCK] Removing vars...")
375    removevars (fs, bl.nactvar)
376    --printf("[LEAVEBLOCK] ...Vars removed")
377    if bl.upval then
378       luaK:codeABC (fs, "OP_CLOSE", bl.nactvar, 0, 0)
379    end
380    -- a block either controls scope or breaks (never both)
381    assert (not bl.isbreakable or not bl.upval)
382    assert (bl.nactvar == fs.nactvar)
383    fs.freereg = fs.nactvar  -- free registers
384    luaK:patchtohere (fs, bl.breaklist)
385 end
386
387
388 ------------------------------------------------------------------------
389 -- read a list of expressions from a list of ast [astlist]
390 -- starts at the [offset]th element of the list (defaults to 1)
391 ------------------------------------------------------------------------
392 local function explist(fs, astlist, v, offset)
393   offset = offset or 1
394   if #astlist < offset then error "I don't handle empty expr lists yet" end
395   --printf("[EXPLIST] about to precompile 1st element %s", disp.ast(astlist[offset]))
396   expr.expr (fs, astlist[offset], v)
397   --printf("[EXPLIST] precompiled first element v=%s", tostringv(v))
398   for i = offset+1, #astlist do
399     luaK:exp2nextreg (fs, v)
400     --printf("[EXPLIST] flushed v=%s", tostringv(v))
401     expr.expr (fs, astlist[i], v)
402     --printf("[EXPLIST] precompiled element v=%s", tostringv(v))
403   end
404   return #astlist - offset + 1
405 end
406
407 ------------------------------------------------------------------------
408 -- 
409 ------------------------------------------------------------------------
410 local function funcargs (fs, ast, v, idx_from)
411   local args = { }  -- expdesc
412   local nparams
413   if #ast < idx_from then args.k = "VVOID" else
414      explist(fs, ast, args, idx_from)
415      luaK:setmultret(fs, args)
416   end
417   assert(v.k == "VNONRELOC")
418   local base = v.info  -- base register for call
419   if hasmultret(args.k) then nparams = luaK.LUA_MULTRET else -- open call
420     if args.k ~= "VVOID" then 
421        luaK:exp2nextreg(fs, args) end -- close last argument
422     nparams = fs.freereg - (base + 1)
423   end
424   init_exp(v, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
425   luaK:fixline(fs, ast.line)
426   fs.freereg = base + 1  -- call remove function and arguments and leaves
427                          -- (unless changed) one result
428 end
429
430 ------------------------------------------------------------------------
431 -- calculates log value for encoding the hash portion's size
432 ------------------------------------------------------------------------
433 local function log2(x)
434   -- math result is always one more than lua0_log2()
435   local mn, ex = math.frexp(x)
436   return ex - 1
437 end
438
439 ------------------------------------------------------------------------
440 -- converts an integer to a "floating point byte", represented as
441 -- (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm)
442 ------------------------------------------------------------------------
443
444 -- local function int2fb(x)
445 --   local m = 0  -- mantissa
446 --   while x >= 8 do x = math.floor((x + 1) / 2); m = m + 1 end
447 --   return m * 8 + x
448 -- end
449
450 local function int2fb(x)
451    local e = 0
452    while x >= 16 do
453       x = math.floor ( (x+1) / 2)
454       e = e+1
455    end
456    if x<8 then return x
457    else return (e+1) * 8 + x - 8 end
458 end
459
460
461 ------------------------------------------------------------------------
462 -- FIXME: to be unified with singlevar
463 ------------------------------------------------------------------------
464 local function singlevaraux(fs, n, var, base)
465 --[[
466 print("\n\nsinglevaraux: fs, n, var, base")
467 printv(fs)
468 printv(n)
469 printv(var)
470 printv(base)
471 print("\n")
472 --]]
473    if fs == nil then  -- no more levels?
474       init_exp(var, "VGLOBAL", luaP.NO_REG)  -- default is global variable
475       return "VGLOBAL"
476    else
477       local v = searchvar(fs, n)  -- look up at current level
478       if v >= 0 then
479          init_exp(var, "VLOCAL", v)
480          if not base then
481             markupval(fs, v)  -- local will be used as an upval
482          end
483       else  -- not found at current level; try upper one
484          if singlevaraux(fs.prev, n, var, false) == "VGLOBAL" then
485             return "VGLOBAL" end
486          var.info = indexupvalue (fs, n, var)
487          var.k = "VUPVAL"
488          return "VUPVAL"
489       end
490    end
491 end
492
493 ------------------------------------------------------------------------
494 -- 
495 ------------------------------------------------------------------------
496 local function singlevar(fs, varname, var)   
497   if singlevaraux(fs, varname, var, true) == "VGLOBAL" then
498      var.info = luaK:stringK (fs, varname) end
499 end
500
501 ------------------------------------------------------------------------
502 -- 
503 ------------------------------------------------------------------------
504 local function new_localvar (fs, name, n)
505   assert (type (name) == "string")
506   if fs.nactvar + n > MAXVARS then error ("too many local vars") end
507   fs.actvar[fs.nactvar + n] = registerlocalvar (fs, name)
508   --printf("[NEW_LOCVAR] %i = %s", fs.nactvar+n, name)
509 end
510
511 ------------------------------------------------------------------------
512 -- 
513 ------------------------------------------------------------------------
514 local function parlist (fs, ast_params)
515    local dots = (#ast_params > 0 and ast_params[#ast_params].tag == "Dots")
516    local nparams = dots and #ast_params - 1 or #ast_params
517    for i = 1, nparams do
518       assert (ast_params[i].tag == "Id", "Function parameters must be Ids")
519       new_localvar (fs, ast_params[i][1], i-1)
520    end
521    -- from [code_param]:
522    --checklimit (fs, fs.nactvar, self.MAXPARAMS, "parameters")
523    fs.f.numparams = fs.nactvar
524    fs.f.is_vararg = dots and VARARG_ISVARARG or 0 
525    adjustlocalvars (fs, nparams)
526    fs.f.numparams = fs.nactvar --FIXME vararg must be taken in account
527    luaK:reserveregs (fs, fs.nactvar)  -- reserve register for parameters
528 end
529
530 ------------------------------------------------------------------------
531 -- if there's more variables than expressions in an assignment,
532 -- some assignations to nil are made for extraneous vars.
533 -- Also handles multiret functions
534 ------------------------------------------------------------------------
535 local function adjust_assign (fs, nvars, nexps, e)
536   local extra = nvars - nexps
537   if hasmultret (e.k) then
538     extra = extra+1  -- includes call itself
539     if extra <= 0 then extra = 0 end
540     luaK:setreturns(fs, e, extra)  -- call provides the difference
541     if extra > 1 then luaK:reserveregs(fs, extra-1) end
542   else
543     if e.k ~= "VVOID" then 
544        luaK:exp2nextreg(fs, e) end  -- close last expression
545     if extra > 0 then
546       local reg = fs.freereg
547       luaK:reserveregs(fs, extra)
548       luaK:_nil(fs, reg, extra)
549     end
550   end
551 end
552
553
554 ------------------------------------------------------------------------
555 -- 
556 ------------------------------------------------------------------------
557 local function enterlevel (fs)
558    fs.nestlevel = fs.nestlevel + 1
559    assert (fs.nestlevel <= LUA_MAXPARSERLEVEL, "too many syntax levels")
560 end
561
562 ------------------------------------------------------------------------
563 -- 
564 ------------------------------------------------------------------------
565 local function leavelevel (fs)
566   fs.nestlevel = fs.nestlevel - 1
567 end
568
569 ------------------------------------------------------------------------
570 -- Parse conditions in if/then/else, while, repeat
571 ------------------------------------------------------------------------
572 local function cond (fs, ast)
573    local v = { }
574    expr.expr(fs, ast, v)  -- read condition
575    if v.k == "VNIL" then v.k = "VFALSE" end  -- 'falses' are all equal here
576    luaK:goiftrue (fs, v)
577    return v.f
578 end
579
580 ------------------------------------------------------------------------
581 -- 
582 ------------------------------------------------------------------------
583 local function chunk (fs, ast)
584    enterlevel (fs)
585    assert (not ast.tag)
586    for i=1, #ast do 
587       stat.stat (fs, ast[i]); 
588       fs.freereg = fs.nactvar
589    end
590    leavelevel (fs)
591 end
592
593 ------------------------------------------------------------------------
594 -- 
595 ------------------------------------------------------------------------
596 local function block (fs, ast)
597   local bl = {}
598   enterblock (fs, bl, false)
599   for i=1, #ast do
600      stat.stat (fs, ast[i])
601      fs.freereg = fs.nactvar
602   end
603   assert (bl.breaklist == luaK.NO_JUMP)
604   leaveblock (fs)
605 end  
606
607 ------------------------------------------------------------------------
608 -- Forin / Fornum body parser
609 -- [fs]
610 -- [body]
611 -- [base]
612 -- [nvars]
613 -- [isnum]
614 ------------------------------------------------------------------------
615 local function forbody (fs, ast_body, base, nvars, isnum)
616    local bl = {}  -- BlockCnt
617    adjustlocalvars (fs, 3)  -- control variables
618    local prep = 
619       isnum and luaK:codeAsBx (fs, "OP_FORPREP", base, luaK.NO_JUMP)
620       or luaK:jump (fs) 
621    enterblock (fs, bl, false)  -- loop block
622    adjustlocalvars (fs, nvars)  -- scope for declared variables
623    luaK:reserveregs (fs, nvars)
624    block (fs, ast_body)
625    leaveblock (fs)
626    --luaK:patchtohere (fs, prep-1)
627    luaK:patchtohere (fs, prep)
628    local endfor = 
629       isnum and luaK:codeAsBx (fs, "OP_FORLOOP", base, luaK.NO_JUMP)
630       or luaK:codeABC (fs, "OP_TFORLOOP", base, 0, nvars)
631    luaK:fixline (fs, ast_body.line)  -- pretend that 'OP_FOR' starts the loop
632    luaK:patchlist (fs, isnum and endfor or luaK:jump(fs), prep + 1)
633 end
634
635
636 ------------------------------------------------------------------------
637 --
638 ------------------------------------------------------------------------
639 local function recfield (fs, ast, cc)
640   local reg = fs.freereg
641   local key, val = {}, {}  -- expdesc
642   --FIXME: expr + exp2val = index -->
643   --       check reduncancy between exp2val and exp2rk
644   cc.nh = cc.nh + 1
645   expr.expr(fs, ast[1], key); 
646   luaK:exp2val (fs, key) 
647   local keyreg = luaK:exp2RK (fs, key)
648   expr.expr(fs, ast[2], val)
649   local valreg = luaK:exp2RK (fs, val)
650   luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, keyreg, valreg)
651   fs.freereg = reg  -- free registers
652 end
653
654
655 ------------------------------------------------------------------------
656 --
657 ------------------------------------------------------------------------
658 local function listfield(fs, ast, cc)
659   expr.expr(fs, ast, cc.v)
660   assert (cc.na <= luaP.MAXARG_Bx) -- FIXME check <= or <
661   cc.na = cc.na + 1
662   cc.tostore = cc.tostore + 1
663 end
664
665 ------------------------------------------------------------------------
666 --
667 ------------------------------------------------------------------------
668 local function closelistfield(fs, cc)
669    if cc.v.k == "VVOID" then return end  -- there is no list item
670    luaK:exp2nextreg(fs, cc.v)
671    cc.v.k = "VVOID"
672    if cc.tostore == luaP.LFIELDS_PER_FLUSH then
673       luaK:setlist (fs, cc.t.info, cc.na, cc.tostore)
674       cc.tostore = 0
675    end
676 end
677
678 ------------------------------------------------------------------------
679 -- The last field might be a call to a multireturn function. In that
680 -- case, we must unfold all of its results into the list.
681 ------------------------------------------------------------------------
682 local function lastlistfield(fs, cc)
683   if cc.tostore == 0 then return end
684   if hasmultret (cc.v.k) then
685     luaK:setmultret(fs, cc.v)
686     luaK:setlist (fs, cc.t.info, cc.na, luaK.LUA_MULTRET)
687     cc.na = cc.na - 1
688   else
689     if cc.v.k ~= "VVOID" then luaK:exp2nextreg(fs, cc.v) end
690     luaK:setlist (fs, cc.t.info, cc.na, cc.tostore)
691   end
692 end
693 ------------------------------------------------------------------------
694 ------------------------------------------------------------------------
695 -- 
696 -- Statement parsers table
697 -- 
698 ------------------------------------------------------------------------
699 ------------------------------------------------------------------------
700
701 function stat.stat (fs, ast)
702    if ast.line then fs.lastline = ast.line end
703    -- debugf (" - Statement %s", disp.ast (ast) )
704
705    if not ast.tag then chunk (fs, ast) else
706
707       local parser = stat [ast.tag]
708       if not parser then 
709          error ("A statement cannot have tag `"..ast.tag) end
710       parser (fs, ast)
711    end
712    --debugf (" - /Statement `%s", ast.tag or "<nil>")
713    debugf (" - /Statement `%s", ast.tag)
714 end
715
716 ------------------------------------------------------------------------
717
718 stat.Do = block
719
720 ------------------------------------------------------------------------
721
722 function stat.Break (fs, ast)
723    local bl, upval = fs.bl, false
724    while bl and not bl.isbreakable do
725       if bl.upval then upval = true end
726       bl = bl.previous
727    end
728    assert (bl, "no loop to break")
729    if upval then luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0) end
730    bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
731 end
732
733 ------------------------------------------------------------------------
734
735 function stat.Return (fs, ast)
736    local e = {}  -- expdesc
737    local first -- registers with returned values
738    local nret = #ast
739
740    if nret == 0 then first = 0
741    else
742       --printf("[RETURN] compiling explist")
743       explist (fs, ast, e)
744       --printf("[RETURN] explist e=%s", tostringv(e))
745       if hasmultret (e.k) then
746          luaK:setmultret(fs, e)
747          if e.k == "VCALL" and nret == 1 then
748             luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
749             assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
750          end
751          first = fs.nactvar
752          nret = luaK.LUA_MULTRET  -- return all values
753       elseif nret == 1 then 
754          --printf("[RETURN] 1 val: e=%s", tostringv(e))
755          first = luaK:exp2anyreg(fs, e)
756          --printf("[RETURN] 1 val in reg %i", first)
757       else
758          --printf("* Return multiple vals in nextreg %i", fs.freereg)
759          luaK:exp2nextreg(fs, e)  -- values must go to the 'stack'
760          first = fs.nactvar  -- return all 'active' values
761          assert(nret == fs.freereg - first)
762       end
763    end
764    luaK:ret(fs, first, nret)
765 end
766 ------------------------------------------------------------------------
767
768 function stat.Local (fs, ast)
769   local names, values = ast[1], ast[2]
770   for i = 1, #names do new_localvar (fs, names[i][1], i-1) end
771   local e = { }
772   if #values == 0 then e.k = "VVOID" else explist (fs, values, e) end
773   adjust_assign (fs, #names, #values, e)
774   adjustlocalvars (fs, #names)
775 end
776
777 ------------------------------------------------------------------------
778
779 function stat.Localrec (fs, ast)
780    assert(#ast[1]==1 and #ast[2]==1, "Multiple letrecs not implemented yet")
781    local ast_var, ast_val, e_var, e_val = ast[1][1], ast[2][1], { }, { }
782    new_localvar (fs, ast_var[1], 0)
783    init_exp (e_var, "VLOCAL", fs.freereg)
784    luaK:reserveregs (fs, 1)
785    adjustlocalvars (fs, 1)
786    expr.expr (fs, ast_val, e_val)
787    luaK:storevar (fs, e_var, e_val)
788    getlocvar (fs, fs.nactvar-1).startpc = fs.pc
789 end
790
791 ------------------------------------------------------------------------
792
793 function stat.If (fs, ast)
794   local astlen = #ast
795   -- Degenerate case #1: no statement
796   if astlen==0 then return block(fs, { }) end
797   -- Degenerate case #2: only an else statement
798   if astlen==1 then return block(fs, ast[1]) end   
799
800   local function test_then_block (fs, test, body)
801     local condexit = cond (fs, test); 
802     block (fs, body) 
803     return condexit
804   end
805
806   local escapelist = luaK.NO_JUMP
807
808   local flist = test_then_block (fs, ast[1], ast[2]) -- 'then' statement
809   for i = 3, #ast - 1, 2 do -- 'elseif' statement
810     escapelist = luaK:concat( fs, escapelist, luaK:jump(fs))
811     luaK:patchtohere (fs, flist)
812     flist = test_then_block (fs, ast[i], ast[i+1])
813   end
814   if #ast % 2 == 1 then -- 'else' statement
815     escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
816     luaK:patchtohere(fs, flist)
817     block (fs, ast[#ast])
818   else
819     escapelist = luaK:concat(fs, escapelist, flist)
820   end
821   luaK:patchtohere(fs, escapelist)
822 end
823
824 ------------------------------------------------------------------------
825
826 function stat.Forin (fs, ast)
827    local vars, vals, body = ast[1], ast[2], ast[3]
828    -- imitating forstat:
829    local bl = { }
830    enterblock (fs, bl, true)
831    -- imitating forlist:
832    local e, base = { }, fs.freereg
833    new_localvar (fs, "(for generator)", 0)
834    new_localvar (fs, "(for state)", 1)
835    new_localvar (fs, "(for control)", 2)
836    for i = 1, #vars do new_localvar (fs, vars[i][1], i+2) end
837    explist (fs, vals, e)
838    adjust_assign (fs, 3, #vals, e)
839    luaK:checkstack (fs, 3)
840    forbody (fs, body, base, #vars, false)
841    -- back to forstat:
842    leaveblock (fs)
843 end
844
845 ------------------------------------------------------------------------
846
847 function stat.Fornum (fs, ast)
848
849    local function exp1 (ast_e)
850       local e = { }
851       expr.expr (fs, ast_e, e)
852       luaK:exp2nextreg (fs, e)
853    end
854    -- imitating forstat:
855    local bl = { }
856    enterblock (fs, bl, true)
857    -- imitating fornum:
858    local base = fs.freereg
859    new_localvar (fs, "(for index)", 0)
860    new_localvar (fs, "(for limit)", 1)
861    new_localvar (fs, "(for step)", 2)
862    new_localvar (fs, ast[1][1], 3) 
863    exp1 (ast[2]) -- initial value
864    exp1 (ast[3]) -- limit
865    if #ast == 5 then exp1 (ast[4]) else -- default step = 1
866       luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
867       luaK:reserveregs(fs, 1)
868    end
869    forbody (fs, ast[#ast], base, 1, true)
870    -- back to forstat:
871    leaveblock (fs)
872 end
873
874 ------------------------------------------------------------------------
875 function stat.Repeat (fs, ast)
876   local repeat_init = luaK:getlabel (fs)
877   local bl1, bl2 = { }, { }
878   enterblock (fs, bl1, true)
879   enterblock (fs, bl2, false)
880   chunk (fs, ast[1])
881   local condexit = cond (fs, ast[2])
882   if not bl2.upval then
883     leaveblock (fs)
884     luaK:patchlist (fs, condexit, repeat_init)
885   else
886     stat.Break (fs)
887     luaK:patchtohere (fs, condexit)
888     leaveblock (fs)
889     luaK:patchlist (fs, luaK:jump (fs), repeat_init)
890   end
891   leaveblock (fs)
892 end
893
894 ------------------------------------------------------------------------
895
896 function stat.While (fs, ast)
897    local whileinit = luaK:getlabel (fs)
898    local condexit = cond (fs, ast[1])
899    local bl = { }
900    enterblock (fs, bl, true)
901    block (fs, ast[2])
902    luaK:patchlist (fs, luaK:jump (fs), whileinit)
903    leaveblock (fs)
904    luaK:patchtohere (fs, condexit);
905 end
906
907 ------------------------------------------------------------------------
908
909 -- FIXME: it's cumbersome to write this in this semi-recursive way.
910 function stat.Let (fs, ast)
911    local ast_lhs, ast_vals, e = ast[1], ast[2], { }
912
913    --print "\n\nLet ast_lhs ast_vals:"
914    --print(disp.ast(ast_lhs))
915    --print(disp.ast(ast_vals))
916
917    local function let_aux (lhs, nvars)
918       local legal = { VLOCAL=1, VUPVAL=1, VGLOBAL=1, VINDEXED=1 }
919       --printv(lhs)
920       if not legal [lhs.v.k] then 
921          error ("Bad lhs expr: "..table.tostring(ast_lhs)) 
922       end
923       if nvars < #ast_lhs then -- this is not the last lhs
924          local nv = { v = { }, prev = lhs }
925          expr.expr (fs, ast_lhs [nvars+1], nv.v)
926          if nv.v.k == "VLOCAL" then check_conflict (fs, lhs, nv.v) end
927          let_aux (nv, nvars+1)
928       else -- this IS the last lhs
929          explist (fs, ast_vals, e)
930          if #ast_vals < nvars then            
931             adjust_assign (fs, nvars, #ast_vals, e)
932          elseif #ast_vals > nvars then 
933             adjust_assign (fs, nvars, #ast_vals, e)
934             fs.freereg = fs.freereg - #ast_vals + nvars
935          else -- #ast_vals == nvars (and we're at last lhs)
936             luaK:setoneret (fs, e)  -- close last expression
937             luaK:storevar (fs, lhs.v, e)
938             return  -- avoid default
939          end
940       end
941       init_exp (e, "VNONRELOC", fs.freereg - 1)  -- default assignment
942       luaK:storevar (fs, lhs.v, e)
943    end
944
945    local lhs = { v = { }, prev = nil }
946    expr.expr (fs, ast_lhs[1], lhs.v)
947    let_aux( lhs, 1)
948 end  
949
950 ------------------------------------------------------------------------
951
952 function stat.Call (fs, ast)
953    local v = {  }
954    expr.Call (fs, ast, v)
955    luaP:SETARG_C (luaK:getcode(fs, v), 1)
956 end
957
958 ------------------------------------------------------------------------
959
960 function stat.Method (fs, ast)
961    local v = {  }
962    expr.Method (fs, ast, v)
963 --FIXME: didn't check that, just copied from stat.Call
964    luaP:SETARG_C (luaK:getcode(fs, v), 1)
965 end
966
967
968 local function patch_goto (fs, src, dst)
969
970 end
971
972
973 ------------------------------------------------------------------------
974 -- Goto/Label data:
975 -- fs.labels        :: string => { nactvar :: int; pc :: int }
976 -- fs.forward_gotos :: string => list(int)
977 --
978 -- fs.labels goes from label ids to the number of active variables at
979 -- the label's PC, and that PC
980 --
981 -- fs.forward_gotos goes from label ids to the list of the PC where
982 -- some goto wants to jump to this label. Since gotos are actually made
983 -- up of two instructions OP_CLOSE and OP_JMP, it's the first instruction's
984 -- PC that's stored in fs.forward_gotos
985 --
986 -- Note that backward gotos aren't stored: since their destination is knowns
987 -- when they're compiled, their target is directly set.
988 ------------------------------------------------------------------------
989
990 ------------------------------------------------------------------------
991 -- Set a Label to jump to with Goto
992 ------------------------------------------------------------------------
993 function stat.Label (fs, ast)
994    local label_id = ast[1]
995    if type(label_id)=='table' then label_id=label_id[1] end
996    -- printf("Label %s at PC %i", label_id, fs.pc)
997    -------------------------------------------------------------------
998    -- Register the label, so that future gotos can use it.
999    -------------------------------------------------------------------
1000    if   fs.labels [label_id] then error "Duplicate label in function"
1001    else fs.labels [label_id] = { pc = fs.pc; nactvar = fs.nactvar } end
1002    local gotos = fs.forward_gotos [label_id]
1003    if gotos then 
1004       ----------------------------------------------------------------
1005       -- Patch forward gotos which were targetting this label.
1006       ----------------------------------------------------------------
1007       for _, goto_pc in ipairs(gotos) do
1008          local close_instr  = fs.f.code[goto_pc]
1009          local jmp_instr    = fs.f.code[goto_pc+1]
1010          local goto_nactvar = luaP:GETARG_A (close_instr)
1011          if fs.nactvar < goto_nactvar then 
1012             luaP:SETARG_A (close_instr, fs.nactvar) end
1013          luaP:SETARG_sBx (jmp_instr, fs.pc - goto_pc - 2)
1014       end
1015       ----------------------------------------------------------------
1016       -- Gotos are patched, they can be forgotten about (when the
1017       -- function will be finished, it will be checked that all gotos
1018       -- have been patched, by checking that forward_goto is empty).
1019       ----------------------------------------------------------------
1020       fs.forward_gotos[label_id] = nil
1021    end 
1022 end
1023
1024 ------------------------------------------------------------------------
1025 -- jumps to a label set with stat.Label. 
1026 -- Argument must be a String or an Id
1027 -- FIXME/optim: get rid of useless OP_CLOSE when nactvar doesn't change.
1028 -- Thsi must be done both here for backward gotos, and in
1029 -- stat.Label for forward gotos.
1030 ------------------------------------------------------------------------
1031 function stat.Goto (fs, ast)
1032    local label_id = ast[1]
1033    if type(label_id)=='table' then label_id=label_id[1] end
1034    -- printf("Goto %s at PC %i", label_id, fs.pc)
1035    local label = fs.labels[label_id]
1036    if label then
1037       ----------------------------------------------------------------
1038       -- Backward goto: the label already exists, so I can get its
1039       -- nactvar and address directly. nactvar is used to close
1040       -- upvalues if we get out of scoping blocks by jumping.
1041       ----------------------------------------------------------------
1042       if fs.nactvar > label.nactvar then
1043          luaK:codeABC  (fs, "OP_CLOSE", label.nactvar, 0, 0) end
1044       local offset = label.pc - fs.pc - 1
1045       luaK:codeAsBx (fs, "OP_JMP", 0, offset)
1046    else
1047       ----------------------------------------------------------------
1048       -- Forward goto: will be patched when the matching label is
1049       -- found, forward_gotos[label_id] keeps the PC of the CLOSE
1050       -- instruction just before the JMP. [stat.Label] will use it to
1051       -- patch the OP_CLOSE and the OP_JMP.
1052       ----------------------------------------------------------------
1053       if not fs.forward_gotos[label_id] then 
1054          fs.forward_gotos[label_id] = { } end
1055       table.insert (fs.forward_gotos[label_id], fs.pc)
1056       luaK:codeABC  (fs, "OP_CLOSE", fs.nactvar, 0, 0)
1057       luaK:codeAsBx (fs, "OP_JMP", 0, luaK.NO_JUMP)
1058    end
1059 end
1060
1061 ------------------------------------------------------------------------
1062 ------------------------------------------------------------------------
1063 -- 
1064 -- Expression parsers table
1065 -- 
1066 ------------------------------------------------------------------------
1067 ------------------------------------------------------------------------
1068
1069 function expr.expr (fs, ast, v)
1070    if type(ast) ~= "table" then 
1071       error ("Expr AST expected, got "..table.tostring(ast)) end
1072    if ast.line then fs.lastline = ast.line end
1073    --debugf (" - Expression %s", tostringv (ast))
1074    local parser = expr[ast.tag]
1075    if parser then parser (fs, ast, v)
1076    elseif not ast.tag then 
1077       error ("No tag in expression "..table.tostring(ast))
1078    else 
1079       error ("No parser for node `"..ast.tag) end
1080    debugf (" - /`%s", ast.tag)
1081 end
1082
1083 ------------------------------------------------------------------------
1084
1085 function expr.Nil (fs, ast, v) init_exp (v, "VNIL", 0) end
1086 function expr.True (fs, ast, v) init_exp (v, "VTRUE", 0) end
1087 function expr.False (fs, ast, v) init_exp (v, "VFALSE", 0) end
1088 function expr.String (fs, ast, v) codestring (fs, v, ast[1]) end
1089 function expr.Number (fs, ast, v)
1090    init_exp (v, "VKNUM", 0)
1091    v.nval = ast[1] 
1092 end
1093
1094 function expr.One (fs, ast, v) 
1095    expr.expr (fs, ast[1], v)
1096    luaK:setoneret (fs, v)
1097 end
1098
1099 function expr.Dots (fs, ast, v)
1100    assert (fs.f.is_vararg ~= 0, "No vararg in this function")
1101    -- NEEDSARG flag is set if and only if the function is a vararg,
1102    -- but no vararg has been used yet in its code.
1103    if fs.f.is_vararg < VARARG_NEEDSARG then 
1104       fs.f.is_varag = fs.f.is_vararg - VARARG_NEEDSARG end
1105    init_exp (v, "VVARARG", luaK:codeABC (fs, "OP_VARARG", 0, 1, 0))
1106 end
1107
1108 ------------------------------------------------------------------------
1109
1110 function expr.Table (fs, ast, v)
1111   local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
1112   local cc = { v = { } , na = 0, nh = 0, tostore = 0, t = v }  -- ConsControl
1113   init_exp (v, "VRELOCABLE", pc)
1114   init_exp (cc.v, "VVOID", 0)  -- no value (yet)
1115   luaK:exp2nextreg (fs, v)  -- fix it at stack top (for gc)
1116   for i = 1, #ast do
1117     assert(cc.v.k == "VVOID" or cc.tostore > 0)
1118     closelistfield(fs, cc);
1119     (ast[i].tag == "Key" and recfield or listfield) (fs, ast[i], cc)
1120   end    
1121   lastlistfield(fs, cc)
1122
1123   -- Configure [OP_NEWTABLE] dimensions
1124   luaP:SETARG_B(fs.f.code[pc], int2fb(cc.na)) -- set initial array size
1125   luaP:SETARG_C(fs.f.code[pc], int2fb(cc.nh))  -- set initial table size
1126   --printv(fs.f.code[pc])
1127 end  
1128
1129
1130 ------------------------------------------------------------------------
1131
1132 function expr.Function (fs, ast, v)
1133   local new_fs = open_func(fs)
1134   if ast.line then new_fs.f.lineDefined = ast.line end
1135   parlist (new_fs, ast[1])
1136   chunk (new_fs, ast[2])
1137   close_func (new_fs)
1138   pushclosure(fs, new_fs, v)
1139 end  
1140
1141 ------------------------------------------------------------------------
1142
1143 function expr.Op (fs, ast, v)
1144    if #ast == 2 then
1145       expr.expr (fs, ast[2], v)
1146       luaK:prefix (fs, ast[1], v)
1147    elseif #ast == 3 then
1148       local v2 = { }
1149       expr.expr (fs, ast[2], v)
1150       luaK:infix (fs, ast[1], v)
1151       expr.expr (fs, ast[3], v2)
1152       luaK:posfix (fs, ast[1], v, v2)
1153    else
1154       error "Wrong arg number"
1155    end
1156 end  
1157
1158 ------------------------------------------------------------------------
1159
1160 function expr.Call (fs, ast, v)
1161    expr.expr (fs, ast[1], v)
1162    luaK:exp2nextreg (fs, v)
1163    funcargs(fs, ast, v, 2)
1164    --debugf("after expr.Call: %s, %s", v.k, luaP.opnames[luaK:getcode(fs, v).OP])
1165 end  
1166
1167 ------------------------------------------------------------------------
1168 -- `Method{ table key args }
1169 function expr.Method (fs, ast, v)
1170    expr.expr (fs, ast[1], v)
1171    luaK:dischargevars (fs, v)
1172    local key = { }
1173    codestring (fs, key, ast[2][1])
1174    luaK:_self (fs, v, key)
1175    funcargs (fs, ast, v, 3)
1176 end  
1177
1178 ------------------------------------------------------------------------
1179
1180 function expr.Index (fs, ast, v)
1181    if #ast ~= 2 then error "generalized indexes not implemented" end
1182
1183    expr.expr (fs, ast[1], v)
1184    luaK:exp2anyreg (fs, v)
1185
1186    local k = { }
1187    expr.expr (fs, ast[2], k)
1188    luaK:exp2val (fs, k)
1189    luaK:indexed (fs, v, k)
1190 end  
1191
1192 ------------------------------------------------------------------------
1193
1194 function expr.Id (fs, ast, v)
1195    assert (ast.tag == "Id")
1196    singlevar (fs, ast[1], v)
1197 end
1198
1199 ------------------------------------------------------------------------
1200
1201 -- function expr.Stat (fs, ast, v)
1202 --    -- Protect temporary stack values as phony local vars:
1203 --    -- this way, they won't be overwritten.
1204 --    local save_nactvar = fs.nactvar
1205 --    -- Eventually, the result should go on top of stack, 
1206 --    -- whose index is saved in dest_reg.
1207 --    local dest_reg = fs.freereg
1208
1209 --    -- the part of actvar which is over nactvar might be filled with local var
1210 --    -- indexes, although these variables don't have a register yet, typically in
1211 --    -- `Local{ {...}, { `Stat{ ... } } }. Save them to restore them.
1212 --    -- The computation of [last_unreg_var] is hackish because [fs.actvar] is
1213 --    -- indexed form 0, and lua is much more comfortable with arrays starting
1214 --    -- at 1.
1215 --    local save_actvar = { }
1216 --    local last_unreg_var = #fs.actvar
1217 --    if last_unreg_var > 0 or fs.actvar[0] then 
1218 --       for i = fs.nactvar, last_unreg_var do
1219 --          --printf("[STAT] save unregistered variable %i -> %i", i, fs.actvar[i])
1220 --          save_actvar[i] = fs.actvar[i]
1221 --       end
1222 --    end
1223 --    fs.nactvar = fs.freereg
1224 --    --printf("[STAT] pretend that there are %i actvars. Entering block...", fs.nactvar)
1225 --    enterblock (fs, { }, false)
1226 --    chunk (fs, ast[1])
1227 --    --printf("[STAT] result expr = %s", disp.ast (ast[2]))
1228 --    expr.expr (fs, ast[2], v)
1229 --    --printf("[STAT] v == %s must go to reg %i", tostringv(v), dest_reg)   
1230 --    -- Push the result on top of stack:
1231
1232 -- -- FIXME: s'il y a des upvalues dans le bloc, il ne faut pas ecrire directement
1233 -- -- dans dest_reg, mais [1] ecrire dans l'actuel freereg [2] fermer le bloc et
1234 -- -- [3] transferer l'ancien freereg dans dest_reg.
1235 -- -- Sinon, le CLOSE ne sera pas appele, et les upvalue ne seront pas fermees.
1236
1237 --    luaK:exp2reg (fs, v, dest_reg)
1238 --    --printf("[STAT] leaving block...")
1239 --    leaveblock (fs)
1240 --    --printf("[STAT] ...block leaved, nactvar back to %i", save_nactvar)
1241 --    assert (dest_reg == fs.freereg)
1242 --    -- Reserve the newly allocated stack level
1243 --    fs.freereg=fs.freereg+1
1244 --    -- Push back nactvar, so that intermediate stacked value stop
1245 --    -- being protected.
1246 --    fs.nactvar = save_nactvar
1247
1248 --    -- restore messed-up unregistered local vars
1249 --    for i, j in pairs(save_actvar) do
1250 --       fs.actvar[i] = j
1251 --    end
1252 -- end
1253
1254 function expr.Stat (fs, ast, v)
1255    -- Protect temporary stack values as phony local vars:
1256    -- this way, they won't be overwritten.
1257    local save_nactvar = fs.nactvar
1258    -- Eventually, the result should go on top of stack, 
1259    -- whose index is saved in dest_reg.
1260    local dest_reg = fs.freereg
1261
1262    -- the part of actvar which is over nactvar might be filled with local var
1263    -- indexes, although these variables don't have a register yet, typically in
1264    -- `Local{ {...}, { `Stat{ ... } } }. Save them to restore them.
1265    -- The computation of [last_unreg_var] is hackish because [fs.actvar] is
1266    -- indexed form 0, and lua is much more comfortable with arrays starting
1267    -- at 1.
1268    local save_actvar = { }
1269    local last_unreg_var = #fs.actvar
1270    if last_unreg_var > 0 or fs.actvar[0] then 
1271       for i = fs.nactvar, last_unreg_var do
1272          save_actvar[i] = fs.actvar[i]
1273       end
1274    end
1275    fs.nactvar = fs.freereg
1276    enterblock (fs, { }, false)
1277    chunk (fs, ast[1])
1278    expr.expr (fs, ast[2], v)
1279    luaK:exp2nextreg (fs, v)
1280    leaveblock (fs)
1281    luaK:exp2reg (fs, v, dest_reg)
1282
1283    -- Reserve the newly allocated stack level
1284    fs.freereg = fs.freereg+1
1285    -- Push back nactvar, so that intermediate stacked value stop
1286    -- being protected.
1287    fs.nactvar = save_nactvar
1288
1289    -- restore messed-up unregistered local vars
1290    for i, j in pairs(save_actvar) do
1291       fs.actvar[i] = j
1292    end
1293 end
1294
1295
1296
1297 ------------------------------------------------------------------------
1298 -- Main function: ast --> proto
1299 ------------------------------------------------------------------------
1300 function metalua_compile (ast, source)
1301   local fs = open_func (nil)
1302   fs.f.is_vararg = VARARG_ISVARARG
1303   chunk (fs, ast)
1304   close_func (fs)
1305   assert (fs.prev == nil)
1306   assert (fs.f.nups == 0)
1307   assert (fs.nestlevel == 0)
1308   if source then fs.f.source = source end
1309   return fs.f
1310 end