diff options
author | Benoit Giannangeli <giann@users.noreply.github.com> | 2017-03-01 11:54:57 +0100 |
---|---|---|
committer | Benoit Giannangeli <benoit.giannangeli@boursorama.fr> | 2017-03-01 12:19:22 +0100 |
commit | 166b951b9d05eff654ef664124f17c8a37f418a6 (patch) | |
tree | a783d5f05cd640d06065c514b87bc7cf74f5e506 /src/lobject.js | |
parent | 94a301a27a8a75c4684790a99a898262b8354f68 (diff) | |
parent | 444182dbbb18f44cf7cafc378f092c28006be365 (diff) | |
download | fengari-166b951b9d05eff654ef664124f17c8a37f418a6.tar.gz fengari-166b951b9d05eff654ef664124f17c8a37f418a6.tar.bz2 fengari-166b951b9d05eff654ef664124f17c8a37f418a6.zip |
Merge pull request #2 from giann/feature/lex-parse
Lexing & Parsing
Diffstat (limited to 'src/lobject.js')
-rw-r--r-- | src/lobject.js | 197 |
1 files changed, 188 insertions, 9 deletions
diff --git a/src/lobject.js b/src/lobject.js index 086af00..bd234a1 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -1,8 +1,12 @@ -/*jshint esversion: 6 */ + /*jshint esversion: 6 */ "use strict"; -const CT = require('./lua.js').constant_types; -const UpVal = require('./lfunc.js').UpVal; +const assert = require('assert'); + +const ljstype = require('./ljstype.js'); +const lua = require('./lua.js'); +const CT = lua.constant_types; +const UpVal = require('./lfunc.js').UpVal; class TValue { @@ -122,6 +126,7 @@ class Table extends TValue { // Those lua values are used by value, others by reference if (key instanceof TValue && [CT.LUA_TNIL, + CT.LUA_TBOOLEAN, CT.LUA_TSTRING, CT.LUA_TSHRSTR, CT.LUA_TLNGSTR, @@ -199,6 +204,18 @@ class CClosure extends TValue { } +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +class LocVar { + constructor() { + this.varname = null; + this.startpc = NaN; /* first point where variable is active */ + this.endpc = NaN; /* first point where variable is dead */ + } +} + const RETS = "..."; const PRE = "[string \""; const POS = "\"]"; @@ -223,7 +240,7 @@ const luaO_chunkid = function(source, bufflen) { let nli = source.indexOf('\n'); /* find first new line (if any) */ let nl = nli ? source.slice(nli) : null; out = `${PRE}`; /* add prefix */ - bufflen -= PRE.length - RETS.length; - POS.length + 1; /* save space for prefix+suffix+'\0' */ + bufflen -= PRE.length + RETS.length + POS.length + 1; /* save space for prefix+suffix+'\0' */ if (l < bufflen && nl === null) { /* small one-line source? */ out += `${source}`; /* keep it */ } else { @@ -237,8 +254,170 @@ const luaO_chunkid = function(source, bufflen) { return out; }; -module.exports.LClosure = LClosure; -module.exports.CClosure = CClosure; -module.exports.TValue = TValue; -module.exports.Table = Table; -module.exports.luaO_chunkid = luaO_chunkid;
\ No newline at end of file +const luaO_hexavalue = function(c) { + if (ljstype.lisdigit(c)) return c.charCodeAt(0) - '0'.charCodeAt(0); + else return (c.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0)) + 10; +}; + +const UTF8BUFFSZ = 8; + +const luaO_utf8desc = function(buff, x) { + let n = 1; /* number of bytes put in buffer (backwards) */ + assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = String.fromCharCode(x); + else { /* need continuation bytes */ + let mfb = 0x3f; /* maximum that fits in first byte */ + do { + buff[UTF8BUFFSZ - (n++)] = String.fromCharCode(0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = String.fromCharCode((~mfb << 1) | x); /* add first byte */ + } + return n; +}; + +const l_str2dloc = function(s, result, mode) { + result[0] = mode === 'x' ? parseInt(s, '16') : parseInt(s); + if (isNaN(result[0])) return null; /* nothing recognized? */ + while (ljstype.lisspace(result[0])) result[0] = result[0].slice(1); /* skip trailing spaces */ + return result[0] === '\0' ? result : null; /* OK if no trailing characters */ +}; + +const l_str2d = function(s) { + let result = [null, null]; + let pidx = /[.xXnN]/g.exec(s).index; + let pmode = pidx ? s.slice(pidx) : null; + let mode = pmode ? pmode.toLowerCase() : 0; + if (mode === 'n') /* reject 'inf' and 'nan' */ + return null; + let end = l_str2dloc(s, result, mode)[0]; /* try to convert */ + if (end === null) { /* failed? may be a different locale */ + throw new Error("Locale not available to handle number"); // TODO + } + return [end, result[1]]; +}; + +const MAXBY10 = Number.MAX_SAFE_INTEGER / 10; +const MAXLASTD = Number.MAX_SAFE_INTEGER % 10; + +const l_str2int = function(s) { + let result = [null, null]; + let a = 0; + let empty = true; + let neg; + + while (ljstype.lisspace(s[0])) s = s.slice(1); /* skip initial spaces */ + neg = s[0] === '-'; + + if (neg || s[0] === '+') + s = s.slice(1); + + if (s[0] === '0' && (s[1] === 'x' || s[1] === 'X')) { /* hex? */ + s = s.slice(2); /* skip '0x' */ + + for (; ljstype.lisxdigit(s[0]); s = s.slice(1)) { + a = a * 16 + luaO_hexavalue(s); + empty = false; + } + } else { /* decimal */ + for (; ljstype.lisdigit(s[0]); s = s.slice(1)) { + let d = parseInt(s[0]); + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return null; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = false; + } + } + + while (ljstype.lisspace(s[0])) s = s.slice(1); /* skip trailing spaces */ + + if (empty)/* TODO: || s[0] !== "") */ return null; /* something wrong in the numeral */ + else { + result[1] = neg ? -a : a; + result[0] = s; + return result; + } +}; + +const luaO_str2num = function(s) { + let s2i = l_str2int(s); + let e = s2i[0]; + let i = s2i[1]; + + if (e !== null) { /* try as an integer */ + return new TValue(CT.LUA_TNUMINT, i); + } else { /* else try as a float */ + s2i = l_str2d(s); + e = s2i[0]; + i = s2i[1]; + + if (e !== null) { + return new TValue(CT.LUA_TNUMFLT, i); + } else + return false; /* conversion failed */ + } +}; + +/* +** converts an integer to a "floating point byte", represented as +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee !== 0 and (xxx) otherwise. +*/ +const luaO_int2fb = function(x) { + let e = 0; /* exponent */ + if (x < 8) return x; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ + e++; + } + return ((e+1) << 3) | (x - 8); +}; + +const intarith = function(L, op, v1, v2) { + switch (op) { + case lua.LUA_OPADD: return (v1 + v2)|0; + case lua.LUA_OPSUB: return (v1 - v2)|0; + case lua.LUA_OPMUL: return (v1 * v2)|0; + case lua.LUA_OPMOD: return (v1 % v2)|0; + case lua.LUA_OPIDIV: return (v1 / v2)|0; + case lua.LUA_OPBAND: return (v1 & v2)|0; + case lua.LUA_OPBOR: return (v1 | v2)|0; + case lua.LUA_OPBXOR: return (v1 ^ v2)|0; + case lua.LUA_OPSHL: return (v1 << v2)|0; + case lua.LUA_OPSHR: return (v1 >> v2)|0; + case lua.LUA_OPUNM: return (-v1)|0; + case lua.LUA_OPBNOT: return (~v1)|0; + } +}; + + +const numarith = function(L, op, v1, v2) { + switch (op) { + case lua.LUA_OPADD: return v1 + v2; + case lua.LUA_OPSUB: return v1 - v2; + case lua.LUA_OPMUL: return v1 * v2; + case lua.LUA_OPDIV: return v1 / v2; + case lua.LUA_OPPOW: return Math.pow(v1, v2); + case lua.LUA_OPIDIV: return (v1 / v2)|0; + case lua.LUA_OPUNM: return -v1; + case lua.LUA_OPMOD: return v1 % v2; + } +}; + +module.exports.CClosure = CClosure; +module.exports.LClosure = LClosure; +module.exports.LocVar = LocVar; +module.exports.TValue = TValue; +module.exports.Table = Table; +module.exports.UTF8BUFFSZ = UTF8BUFFSZ; +module.exports.luaO_chunkid = luaO_chunkid; +module.exports.luaO_hexavalue = luaO_hexavalue; +module.exports.luaO_int2fb = luaO_int2fb; +module.exports.luaO_str2num = luaO_str2num; +module.exports.luaO_utf8desc = luaO_utf8desc;
\ No newline at end of file |