summaryrefslogtreecommitdiff
path: root/src/lfunc.js
blob: db623b53784f638ec9c3d717630e0a24f3629513 (plain)
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
/*jshint esversion: 6 */
"use strict";
const assert  = require('assert');

const defs    = require('./defs.js');
const lobject = require('./lobject.js');
const CT      = defs.constant_types;

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 open: stack index. if closed: null (find value in this.u.value) */
        this.refcount = 0;
        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) {
        if (this.v !== null) {
            this.L.stack[this.v] = L.stack[ra];
        } else {
            this.u.value.setfrom(L.stack[ra]);
        }
    }

    isopen() {
        return this.v !== null;
    }

}

const luaF_newLclosure = function(L, n) {
    let c = new lobject.LClosure(L, n);
    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.u.open.next = pp;
    uv.u.open.touched = true;

    L.openupval = uv;

    uv.v = level;

    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) {
            let from = L.stack[uv.v];
            uv.u.value = new lobject.TValue(from.type, from.value);
            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 = new lobject.TValue(CT.LUA_TNIL, null);
        uv.v = null;
        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;