UNPKG

mkjs-cli

Version:
268 lines (225 loc) 6.22 kB
const fs = require('fs'); const path = require('path'); const vm = require('vm'); const T_EVAL_TIMEOUT = 8000; // 8 seconds const h_eval = { verbatim(h_verbatim) { return h_verbatim.value; }, inline(h_inline, y_context) { let z_result = this.run(h_inline.code, y_context); return h_inline.suppress? '': z_result+''; }, if(h_if) { if(this.run(h_if.if)) { return this.eval(h_if.then); } else { let s_output = ''; let b_elseifs = h_if.elseifs.some((h) => { if(this.run(h.if)) { s_output = this.eval(h.then); return true; } }); if(!b_elseifs && this.run(h_if.else)) { s_output = this.eval(h_if.else); } return s_output; } }, macro(h_macro) { let f_macro = this.evaluate(`function ${h_macro.def} { let __JMACS_OUTPUT = ''; ${h_macro.body.map(this.codify).join('\n')} return __JMACS_OUTPUT; }`); debugger; this.macros[f_macro.name] = f_macro; return ''; }, include(h_include, h_context) { let s_file = this.evaluate(h_include.file, h_context); let p_file = path.resolve(this.cwd, s_file); let s_input = fs.readFileSync(p_file, 'utf8'); let h_result = require('./compiler')({ input: s_input, cwd: path.dirname(p_file), }); if(h_result.error) { throw h_result.error; } // merge macros and globals let h_include_macros = h_result.macros; for(let s_macro in h_include_macros) { this.macros[s_macro] = h_include_macros[s_macro]; } let h_include_global = h_result.global; for(let s_global in h_include_global) { this.global[s_global] = h_include_global[s_global]; } // append output return h_result.output; }, }; const h_codify = { verbatim: h => `__JMACS_OUTPUT += ${JSON.stringify(h.value)};`, inline: (s_code, b_suppress) => b_suppress ? s_code : `__JMACS_OUTPUT += (${s_code});`, if(h_if) { let s_output = `if(${h_if.if}) { ${this.codify(h_if.then)} }`; for(let h_elseif of h_if.elseifs) { s_output += ` else if(${h_elseif.if}) { ${this.codify(h_elseif.then)} }`; } if(h_if.else.length) { s_output += ` else { ${this.codify(h_if.else)} }`; } return s_output; }, }; class evaluator { constructor() { Object.assign(this, { context: vm.createContext({}), }); } codify(z_syntax) { debugger; if(Array.isArray(z_syntax)) { return z_syntax.map(h => this.codify(h).join('\n')); } else { return [h_codify[z_syntax.type].apply(this, [z_syntax])]; } } run(s_code) { // prep script let y_script = new vm.Script(s_code, {}); // eval code return y_script.runInContext(this.context, { timeout: T_EVAL_TIMEOUT, }); } eval(z_syntax) { if(Array.isArray(z_syntax)) { return z_syntax.map(h => this.codify(h).join('\n')); } else { return h_eval[z_syntax.type].apply(this, [z_syntax]); } } } module.exports = (a_sections) => { return function(p_cwd, h_global=null, h_macros={}) { let h_states = { cwd: p_cwd, macros: h_macros, global: h_global, output: '', // evaluate_body(a_body, h_context) { // let s_output = ''; // a_body.forEach((h) => { // s_output += h_program[h.type].apply(this, [h, h_context]); // }); // return s_output; // }, // evaluate(h_expr, h_context, b_no_print=false) { // if(!h_expr) return null; // switch(h_expr.type) { // case 'call': { // let a_args = h_expr.args.map(h => this.evaluate(h, h_context, true)); // let z_out = this.call_macro(h_expr.macro, a_args); // if(h_expr.quiet) return ''; // if(!b_no_print && 'object' === typeof z_out) { // return this.evaluate(z_out, h_context); // } // return z_out; // } // case 'variable': { // let s_name = h_expr.name; // if(s_name in h_context) { // let z_value = h_context[s_name]; // if(!b_no_print && 'object' === typeof z_value) { // if(Array.isArray(z_value)) { // return z_value.map((h_item) => { // return this.evaluate(h_item, h_context); // }).join(', '); // } // else { // return this.evaluate(z_value, h_context); // } // } // else { // return z_value; // } // } // else { // console.warn(`variable '${s_name}' is undefined`); // return null; // // debugger; // // throw 'undefined variable'; // } // } // case 'code': { // let f_parse = module.parent.parent.exports.parse(h_expr.value); // let h_eval = f_parse(p_cwd, h_context, this.macros); // return h_eval.output; // } // default: // debugger; // break; // } // }, // call_macro(s_macro, a_args) { // let h_macro = this.macros[s_macro]; // let s_output = ''; // let h_context = Object.create(this.global); // if(!h_macro) { // // built-in function // if(H_BUILTIN_FUNCTIONS[s_macro]) { // return H_BUILTIN_FUNCTIONS[s_macro](...(a_args.map((z_arg) => { // return ('object' === typeof z_arg && !Array.isArray(z_arg)) // ? this.evaluate(z_arg, h_context, true) // : z_arg; // }))); // } // throw new Error(`no such macro defined: ${s_macro}`); // } // let a_params = h_macro.params; // a_params.forEach((h_param, i_param) => { // h_context[h_param.name] = (a_args.length > i_param) // ? a_args[i_param] // : (h_param.default // ? this.evaluate(h_param.default) // : null); // }); // let a_body = h_macro.body; // let ne_body = a_body.length - 1; // a_body.forEach((h_section, i_section) => { // s_output += h_program[h_section.type].apply(this, [h_section, h_context]); // }); // return s_output; // }, }; let k_evaluator = new evaluator(); let a_output = k_evaluator.eval(a_sections); // // process each section // a_sections.forEach((h_section) => { // h_states.output += h_eval[h_section.type].apply(h_states, [h_section, h_states.global]); // }); let s_eval = `let __JMACS_OUTPUT = '';\n`+a_output.join('\n')+'\n__JMACS_OUTPUT;'; let z_result = k_evaluator.run(s_eval); return { output: z_result, }; }; };