| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | 
const stream = require('stream');const reader = require('./reader.js');const type2llvm = {  'double': 'double',  'int': 'i32'}const argGenerators = {  double: function (name, needStack) {    let code = '';    code += `  // argument: double ${name}\n`;    code += `  if (typeof ${name} !== 'number') {\n`;    if (needStack) code += '    cephes.stackRestore(stacktop);\n';    code += `    throw new TypeError('${name} must be a number');\n`;    code += `  }\n`;    code += `  const carg_${name} = ${name};\n`;    return code;  },  int: function (name, needStack) {    let code = '';    code += `  // argument: int ${name}\n`;    code += `  if (typeof ${name} !== 'number') {\n`;    if (needStack) code += '    cephes.stackRestore(stacktop);\n';    code += `    throw new TypeError('${name} must be a number');\n`;    code += `  }\n`;    code += `  const carg_${name} = ${name} | 0;\n`;    return code;  },  "double*": function (name, needStack) {    let code = '';    code += `  // argument: double* ${name}\n`;    code += `  const carg_${name} = cephes.stackAlloc(8); // No need to zero-set it.\n`;    return code;  },  "int*": function (name, needStack) {    let code = '';    code += `  // argument: int* ${name}\n`;    code += `  const carg_${name} = cephes.stackAlloc(4); // No need to zero-set it.\n`;    return code;  },  "double[]": function (name, needStack) {    let code = '';    code += `  // argument: double[] ${name}\n`;    code += `  if (!(${name} instanceof Float64Array)) {\n`;    if (needStack) code += '    cephes.stackRestore(stacktop);\n';    code += `    throw new TypeError('${name} must be either a Float64Array');\n`;    code += `  }\n`;    code += `  const carg_${name} = cephes.stackAlloc(${name}.length << 3);\n`;    code += `  cephes.writeArrayToMemory(new Uint8Array(${name}.buffer, ${name}.byteOffset, ${name}.byteLength), carg_${name});\n`;    return code;  }};const header = `const cephes = require('./cephes.js');// Export compiled promise, in Node.js this is just a dummy promise as the// WebAssembly program will be compiled synchronously. It takes about 20ms// as of Node.js v10.6.1.exports.compiled = cephes.compiled;`;class InterfaceGenerator extends stream.Transform {  constructor() {    super({ objectMode: true });    this.push(header);  }  _transform(data, encoding, done) {    const {filename, returnType, functionName, functionArgs} = data;    // Check if the stack will be needed because of isPointer or isArray    const needStack = functionArgs.some((arg) => arg.isArray || arg.isPointer);    // Check if there is extra data returned    const extraReturn = functionArgs.some((arg) => arg.isPointer);    //    // Start code generation    //    let code = '';    //    // function header    //    // function name    code += `// from cephes/${filename}.c\n`;    code += `exports.${functionName} = function ${functionName}(`    // function arguments    for (const {type, isPointer, isArray, name} of functionArgs) {      if (isPointer) continue;      code += `/* ${type}${isArray ? '[]' : ''} */ ${name}, `;    }    // Remove training comma    code = code.slice(0, -2);    // finish function header    code += `) {\n`;    if (needStack) {      code += '  //Save the STACKTOP because the following code will do some stack allocs\n';      code += `  const stacktop = cephes.stackSave();\n`;      code += '\n';    }    //    // function arguments    //    for (const {fullType, name} of functionArgs) {      code += argGenerators[fullType](name, needStack);      code += '\n';    }    //    // function call    //    code += `  // return: ${returnType}\n`;    // function call    code += `  const fn_ret = cephes._cephes_${functionName}(`;    // function arguments    for (const { name } of functionArgs) {      code += `carg_${name}, `;    }    // Remove training comma    code = code.slice(0, -2);    // finish function header    code += `)${returnType === 'int' ? ' | 0' : ''};\n`;    code += '\n';    //    // function return    //    if (extraReturn) {      code += '  // There are pointers, so return the values of thoese too\n';      code += '  const ret = [fn_ret, {\n';      for (const { isPointer, name, type } of functionArgs) {        if (!isPointer) continue;        code += `    '${name}': cephes.getValue(carg_${name}, '${type2llvm[type]}'),\n`;      }      code += '  }];\n';    } else {      code += '  // No pointers, so just return fn_ret\n';      code += '  const ret = fn_ret;\n';    }    code += '\n';    //    // function footer    //    if (needStack) {      code += '  // Restore internal stacktop before returning\n';      code += '  cephes.stackRestore(stacktop);\n';    }    code += '  return ret;\n';    code += '};\n';    code += '\n';    done(null, code);  }}process.stdin  .pipe(reader())  .pipe(new InterfaceGenerator())  .pipe(process.stdout)
 |