Skip to content

Commit

Permalink
[js] Add a nqp::p6fakerun that does a fake rakudo run in a new global…
Browse files Browse the repository at this point in the history
… context
  • Loading branch information
pmurias committed Dec 4, 2018
1 parent fdd249a commit 194c84b
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 36 deletions.
2 changes: 2 additions & 0 deletions src/vm/js/Perl6/Ops.nqp
Expand Up @@ -173,3 +173,5 @@ $ops.add_simple_op('p6inpre', $ops.INT, [], :ctx, :side_effects);
$ops.add_simple_op('p6getouterctx', $ops.OBJ, [$ops.OBJ], :decont(0), :!inlinable);

$ops.add_simple_op('p6staticouter', $ops.OBJ, [$ops.OBJ], :ctx, :side_effects);

$ops.add_simple_op('p6fakerun', $ops.OBJ, [$ops.OBJ], :side_effects, :takes_hll);
49 changes: 40 additions & 9 deletions src/vm/js/perl6-runtime/runtime.js
Expand Up @@ -4,14 +4,24 @@ module.exports.load = function(nqp, CodeRef, Capture, containerSpecs) {

let Scalar, True, False, Str, Code, Mu, Signature;

nqp.saveThisGlobalContext(context => {
context.p6binder = nqp.p6binder;
});

nqp.restoreThisGlobalContext(context => {
nqp.p6binder = context.p6binder;
});

op.p6settypes = function(types) {
Scalar = types.content.get('Scalar');
True = types.content.get('True');
False = types.content.get('False');
Str = types.content.get('Str');
Code = types.content.get('Code');
Mu = types.content.get('Mu');
Signature = types.content.get('Signature');
nqp.restoreThisGlobalContext(context => {
Scalar = types.content.get('Scalar');
True = types.content.get('True');
False = types.content.get('False');
Str = types.content.get('Str');
Code = types.content.get('Code');
Mu = types.content.get('Mu');
Signature = types.content.get('Signature');
});

return types;
};
Expand Down Expand Up @@ -193,12 +203,11 @@ module.exports.load = function(nqp, CodeRef, Capture, containerSpecs) {
return cont;
};

const p6HLL = nqp.getHLL('perl6');

op.p6argvmarray = function(ctx, args) {
const array = [];
for (let i=2; i < args.length; i++) {
array[i-2] = nqp.op.hllizefor(ctx, nqp.arg(p6HLL, args[i]), 'perl6');
array[i-2] = nqp.op.hllizefor(ctx, nqp.arg(nqp.getHLL('perl6'), args[i]), 'perl6');
}
return nqp.createArray(array);
};
Expand Down Expand Up @@ -293,6 +302,28 @@ module.exports.load = function(nqp, CodeRef, Capture, containerSpecs) {

};

op.p6fakerun = function(HLL, options) {
const code = options.content.get('code').$$getStr();
const input = options.content.get('input').$$getStr();

const compilerArgs = options.content.get('compiler-args').array;
const args = options.content.get('args').array;

const env = options.content.get('env');

const rakudoLibrary = nqp.requireExtraStuff('./rakudo-library.nqp-raw-runtime');

const result = rakudoLibrary.capturedRun(code, input, compilerArgs, args, env);

const hash = nqp.hash();

hash.content.set('out', nqp.op.box_s(result.out, HLL.get('str_box')));
hash.content.set('err', nqp.op.box_s(result.err, HLL.get('str_box')));
hash.content.set('status', nqp.op.box_i(result.status, HLL.get('int_box')));

return hash;
};

function RakudoScalar(STable) {
this.STable = STable;
}
Expand Down
86 changes: 59 additions & 27 deletions src/vm/js/rakudo-library.js
@@ -1,37 +1,37 @@
const fs = require('fs');
const tmp = require('tmp');

const nqp = require('nqp-runtime');
const oldRun = nqp.run;

const oldArgs = nqp.args;
let passedArgs;

let oldArgs;

nqp.run = function(code) {
nqp.run = oldRun;
return code;
function fakeArgs(isMain) {
return isMain ? passedArgs.map(arg => new nqp.NativeStrArg(arg)) : [];
};

let passedArgs;

nqp.args = function(calledFrom) {
if (calledFrom.parent === module) {
return passedArgs.map(arg => new nqp.NativeStrArg(arg));
}
return oldArgs(calledFrom);
const code = function() {
require('./rakudo.js')(true);
};

const code = require('./rakudo.js');

const core = require('nqp-runtime/core.js');

module.exports.compile = function(source, options = {}) {
const oldGlobalContext = nqp.freshGlobalContext();

const oldArgs = nqp.args;
nqp.args = fakeArgs;
const tmp = require('tmp');
const tmpFile = tmp.tmpNameSync();

passedArgs = ['perl6-js', '--output', tmpFile, '--target=js', source];

const oldWritefh = nqp.op.getstdout().constructor.prototype.$$writefh;
if (Object.prototype.hasOwnProperty.call(nqp.op.getstdout(), '$$writefh')) {
throw `Can't overwrite $$writefh on stdout, it's already set`;
}

const output = [];
nqp.op.getstdout().constructor.prototype.$$writefh = function(buf) {

nqp.op.getstdout().$$writefh = function(buf) {
output.push(core.toRawBuffer(buf));
}

Expand All @@ -44,7 +44,8 @@ module.exports.compile = function(source, options = {}) {
code();
}

nqp.op.getstdout().constructor.prototype.$$writefh = oldWritefh;
delete nqp.op.getstdout().$$writefh;

const lines = Buffer.concat(output).toString().split(/\n/);

const loaded = [];
Expand All @@ -60,11 +61,32 @@ module.exports.compile = function(source, options = {}) {
}
}

nqp.args = oldArgs;

nqp.setGlobalContext(oldGlobalContext);

const fs = require('fs');
return {js: fs.readFileSync(tmpFile, 'utf8'), loaded: loaded};
};

module.exports.capturedRun = function(source, input, compileArgs, args) {
module.exports.capturedRun = function(source, input, compileArgs, args, passedEnv) {
const oldGlobalContext = nqp.freshGlobalContext();

const env = nqp.hash();

passedEnv.content.forEach((value, key, map) => {
env.content.set(key, new nqp.NQPStr(value.$$getStr()));
});

const oldArgs = nqp.args;
nqp.args = fakeArgs;

const oldGetEnvHash = nqp.op.getenvhash;

nqp.op.getenvhash = function() {
return env;
};

const out = [];
const err = [];

Expand All @@ -82,15 +104,21 @@ module.exports.capturedRun = function(source, input, compileArgs, args) {
throw new Exit(status);
};

const oldStdoutWritefh = nqp.op.getstdout().constructor.prototype.$$writefh;
nqp.op.getstdout().constructor.prototype.$$writefh = function(buf) {
if (Object.prototype.hasOwnProperty.call(nqp.op.getstdout(), '$$writefh')) {
throw `Can't overwrite $$writefh on stdout, it's already set`;
}

nqp.op.getstdout().$$writefh = function(buf) {
out.push(core.toRawBuffer(buf));
};

if (Object.prototype.hasOwnProperty.call(nqp.op.getstderr(), '$$writefh')) {
throw `Can't overwrite $$writefh on stderr, it's already set`;
}

const oldStderrWritefh = nqp.op.getstderr().constructor.prototype.$$writefh;
nqp.op.getstderr().constructor.prototype.$$writefh = function(buf) {
nqp.op.getstderr().$$writefh = function(buf) {
err.push(core.toRawBuffer(buf));
}
};

const oldOpen = nqp.op.open;

Expand Down Expand Up @@ -144,11 +172,15 @@ module.exports.capturedRun = function(source, input, compileArgs, args) {
}
}

nqp.op.getstdout().constructor.prototype.$$writefh = oldStdoutWritefh;
nqp.op.getstderr().constructor.prototype.$$writefh = oldStderrWritefh;
delete nqp.op.getstdout().$$writefh;
delete nqp.op.getstderr().$$writefh;

nqp.op.exit = oldExit;
nqp.op.open = oldOpen;
nqp.args = oldArgs;
nqp.op.getenvhash = oldGetEnvHash;

nqp.setGlobalContext(oldGlobalContext);

return {
status: status,
Expand Down

0 comments on commit 194c84b

Please sign in to comment.