123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- /* 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, ' '),
- };
- };
|