summaryrefslogtreecommitdiff
path: root/src/lfunc.js
blob: 40c0905c6970b74d0cd1333fa8f88ac1f5580dd0 (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
/*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.id = L.l_G.id_counter++;
        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() {
        this.L = null; /* Keep track of the thread it comes from */
        this.v = null; /* if open: stack index. if closed: null (find it in this.value) */
        this.open_next = null; /* linked list (when open) */
        this.refcount = 0;
        this.value = null; /* the TValue (when closed) */
    }

    val() {
        return this.v !== null ? this.L.stack[this.v] : this.value;
    }

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

}

const luaF_newLclosure = function(L, n) {
    let c = new lobject.LClosure(L, n);
    return c;
};


const luaF_findupval = function(L, level) {
    let pp = L.openupval;
    let p = pp;
    while (pp !== null && pp.v >= level) {
        p = pp;
        assert(p.isopen());
        if (p.v === level)
            return p;

        pp = p.open_next;
    }

    let uv = new UpVal();

    if (p) {  /* The openupval list is not empty */
        uv.open_next = p;  /* link it to list of open upvalues */
    }

    L.openupval = uv;

    uv.L = L;
    uv.v = level;  /* current value lives in the stack */

    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.open_next; /* remove from 'open' list */
        if (uv.refcount > 0) {
            let from = uv.L.stack[uv.v];
            uv.L = null;
            uv.v = null;
            uv.value = new lobject.TValue(from.type, from.value);
        }
    }
};

/*
** 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.value = new lobject.TValue(CT.LUA_TNIL, 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.getstr();
        }
    }
    return null;  /* not found */
};


module.exports.MAXUPVAL          = 255;
module.exports.Proto             = Proto;
module.exports.UpVal             = UpVal;
module.exports.luaF_findupval         = luaF_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;