1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/*jshint esversion: 6 */
"use strict";
const assert = require('assert');
const lobject = require('./lobject.js');
class Proto {
constructor(L) {
this.k = []; // constants used by the function
this.p = []; // functions defined inside the function
this.code = []; // opcodes
this.cache = null; // last-created closure with this prototype
this.lineinfo = []; // map from opcodes to source lines (debug information)
this.upvalues = []; // upvalue information
this.numparams = 0; // number of fixed parameters
this.is_vararg = 0;
this.maxstacksize = 0; // number of registers needed by this function
this.locvars = []; // information about local variables (debug information)
this.linedefined = 0; // debug information
this.lastlinedefined = 0; // debug information
this.source = null; // used for debug information
}
}
class UpVal {
constructor(L) {
this.L = L; // Keep track of the thread it comes from
this.v = null; /* if null, upval is closed, value is in u.value */
this.u = {
open: { /* (when open) */
next: null, /* linked list */
touched: false /* mark to avoid cycles with dead threads */
},
value: null /* the value (when closed) */
};
}
val(L) {
return this.v !== null ? L.stack[this.v] : this.u.value;
}
setval(L, ra) {
let o = L.stack[ra];
if (this.v !== null) {
this.L.stack[this.v] = new lobject.TValue(o.type, o.value);
} else this.u.value = new lobject.TValue(o.type, o.value);
}
isopen() {
return this.v !== null;
}
}
const luaF_newLclosure = function(L, n) {
let c = new lobject.LClosure();
c.p = null;
c.nupvalues = n;
while (n--) c.upvals[n] = null;
return c;
};
const findupval = function(L, level) {
let pp = L.openupval;
while(pp !== null && pp.v >= level) {
let p = pp;
if (p.v === level)
return p;
pp = p.u.open.next;
}
let uv = new UpVal(L);
uv.refcount = 0;
uv.u.open.next = pp;
uv.u.open.touched = true;
pp = uv;
uv.v = level;
// Thread with upvalue list business ? lfunc.c:75
return uv;
};
const luaF_close = function(L, level) {
while (L.openupval !== null && L.openupval.v >= level) {
let uv = L.openupval;
assert(uv.isopen());
L.openupval = uv.u.open.next; /* remove from 'open' list */
if (uv.refcount > 0) {
uv.value = L.stack[uv.v];
uv.v = null;
}
}
};
/*
** fill a closure with new closed upvalues
*/
const luaF_initupvals = function(L, cl) {
for (let i = 0; i < cl.nupvalues; i++) {
let uv = new UpVal(L);
uv.refcount = 1;
uv.u.value = null;
uv.v = uv.u.value;
cl.upvals[i] = uv;
}
};
/*
** Look for n-th local variable at line 'line' in function 'func'.
** Returns null if not found.
*/
const luaF_getlocalname = function(f, local_number, pc) {
for (let i = 0; i < f.locvars.length && f.locvars[i].startpc <= pc; i++) {
if (pc < f.locvars[i].endpc) { /* is variable active? */
local_number--;
if (local_number === 0)
return f.locvars[i].varname;
}
}
return null; /* not found */
};
module.exports.MAXUPVAL = 255;
module.exports.Proto = Proto;
module.exports.UpVal = UpVal;
module.exports.findupval = findupval;
module.exports.luaF_close = luaF_close;
module.exports.luaF_getlocalname = luaF_getlocalname;
module.exports.luaF_initupvals = luaF_initupvals;
module.exports.luaF_newLclosure = luaF_newLclosure;
|