0
0
mirror of https://github.com/cjdelisle/cjdns synced 2025-10-06 00:32:50 +02:00
Files
cjdns/exception/Er.js
Caleb James DeLisle 0899f770c6 Use strict in javascript
2020-10-02 12:18:52 +02:00

115 lines
4.1 KiB
JavaScript

/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
'use strict';
const trim = (x) => {
if (x[0] !== ' ' || x[x.length-1] !== ' ') {
throw new Error("INTERNAL: Er input must begin " +
"with and end with a space, unrecognized [" + x + "]");
}
return x.trim();
};
const defun = (ctx, spec) => {
trim(spec);
if (spec.lastIndexOf(')') !== spec.length - 2) {
throw new Error("Er function spec must end " +
"with a ), unrecognized [" + spec + "]");
}
let c = 1;
let i = spec.length - 3;
for (; c && i >= 0; i--) {
c += spec[i] === ')';
c -= spec[i] === '(';
}
const args = spec.slice(i + 2, spec.length - 2);
const rettAndFunc = spec.slice(0, i + 1).trim();
const func = rettAndFunc.replace(/^.*\s+([a-zA-Z_][a-zA-Z0-9_]*)$/, (all, a) => a);
//console.log('defun: ' + rettAndFunc + ' - ' + args);
if (func === rettAndFunc) {
throw new Error("Could not parse function [" + spec + "]");
}
const rett = rettAndFunc.replace(/\s+[a-zA-Z_][a-zA-Z0-9_]*$/, '').trim();
ctx.activeFunction = ctx.functions[func] = { rett: rett };
if (rett === 'void') {
return 'struct Er_Ret* ' + func + '(' + args + ')';
} else {
return 'struct Er_Ret* ' + func + '(' + rett + ' *Er_returnValP, ' + args + ')';
}
};
const ret = (ctx, val) => {
val = trim(val);
if (ctx.activeFunction.rett === 'void') {
return 'return (struct Er_Ret*)0';
} else {
return '*Er_returnValP = ' + val + '; return (struct Er_Ret*)0';
}
};
const er = (ctx, assert, errOut, expr, file, line) => {
expr = trim(expr);
if (!/[a-zA-Z_][a-zA-Z0-9_]*\(.*\)$/.test(expr)) {
throw new Error("Er() expr must be in the form Er(funcName(arg1, arg2, ...)) " +
"in [" + expr + "]");
}
const funcName = expr.slice(0, expr.indexOf('('));
const f = ctx.functions[funcName];
if (!f) {
throw new Error("Er() not a defined function [" + funcName + "] in [" + expr + "]");
}
let ifret = `if (Er_ret) { return Er_unwind("${file}", ${line}, Er_ret); }`;
if (assert) {
ifret = `
if (Er_ret) {
struct Er_Ret** Er_errOut = ${errOut ? errOut : '(struct Er_Ret**)0'};
if (Er_errOut) {
*Er_errOut = Er_unwind("${file}", ${line}, Er_ret);
} else {
Er__assertFail(Er_unwind("${file}", ${line}, Er_ret));
}
}
`;
}
if (f.rett === 'void') {
return `do {
struct Er_Ret* Er_ret = ${expr};
${ifret}
} while (0)`;
} else {
const args = expr.slice(expr.indexOf('(') + 1);
return `(__extension__({
${f.rett} Er_returnVal;
__builtin_memset(&Er_returnVal, 0, sizeof(Er_returnVal));
struct Er_Ret* Er_ret = ${funcName}(&Er_returnVal, ${args};
${ifret}
Er_returnVal;
}))`;
}
};
module.exports.create = () => {
const ctx = {
activeFunction: undefined,
functions: {},
};
return {
defun: (spec) => defun(ctx, spec).replace(/\n/g, ' '),
ret: (val) => ret(ctx, val).replace(/\n/g, ' '),
er: (expr, file, line) => er(ctx, false, null, expr, file, line).replace(/\n/g, ' '),
assert: (expr, file, line) => er(ctx, true, null, expr, file, line).replace(/\n/g, ' '),
check: (out, expr, file, line) => er(ctx, true, out, expr, file, line).replace(/\n/g, ' '),
};
};