Spaces:
Running
Running
File size: 5,305 Bytes
8f3f8db |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
// This is a SqueakJS VM for use with node
//
// To start an image use: node squeak_node.js [-ignoreQuit] <image filename>
//
// To start the minimal headless image present in the folder "headless" use:
// node squeak_node.js headless/headless.image
//
// Option "-ignoreQuit" is present to prevent some images from quiting when
// no GUI (support) is found. The image will not be able to quit from within
// the image and needs to be quit by stopping the process itself.
// In some situations adding "-ignoreQuit" can make some minimal images crash
// when no more processes are running (ie when no bytecode is left to execute).
//
// A special ConsolePlugin is loaded which allows sending messages to the console.
// Add the following method to the Smalltalk image (to Object for example):
//
// primLog: messageString level: levelString
//
// "Log messageString to the console. The specified level should be one of:
// 'log'
// 'info'
// 'warn'
// 'error'
// "
//
// <primitive: 'primitiveLog:level:' module: 'ConsolePlugin'>
// ^ self
//
// The VM will try to load plugins when named primitives are used for the first time.
// These plugins do not need to be imported up front.
var os = require("os");
var fs = require("fs");
var process = require("process");
var path = require("path");
// Retrieve image name and parameters from command line
var processArgs = process.argv.slice(2);
var ignoreQuit = processArgs[0] === "-ignoreQuit";
if (ignoreQuit) {
processArgs = processArgs.slice(1);
}
var fullName = processArgs[0];
if (!fullName) {
console.error("No image name specified.");
console.log("Usage (simplified): " + path.basename(process.argv0) + path.basename(process.argv[1]) + " [-ignoreQuit] <image filename>");
process.exit(1);
}
var root = path.dirname(fullName) + path.sep;
var imageName = path.basename(fullName, ".image");
// Create global 'self' resembling the global scope in the browser DOM
Object.assign(global, {
// Add browser element 'self' for platform consistency
self: new Proxy({}, {
get: function(obj, prop) {
return global[prop];
},
set: function(obj, prop, value) {
global[prop] = value;
return true;
}
})
});
// Extend the new global scope with a few browser/DOM classes and methods
Object.assign(self, {
localStorage: {},
WebSocket: typeof WebSocket === "undefined" ? require("./lib_node/WebSocket") : WebSocket,
sha1: require("./lib/sha1"),
btoa: function(string) {
return Buffer.from(string, 'ascii').toString('base64');
},
atob: function(string) {
return Buffer.from(string, 'base64').toString('ascii');
}
});
// Load VM and the internal plugins
require("./globals.js");
require("./vm.js");
require("./vm.object.js");
require("./vm.object.spur.js");
require("./vm.image.js");
require("./vm.interpreter.js");
require("./vm.interpreter.proxy.js");
require("./vm.instruction.stream.js");
require("./vm.instruction.stream.sista.js");
require("./vm.instruction.printer.js");
require("./vm.primitives.js");
require("./jit.js");
require("./vm.display.js");
require("./vm.display.headless.js"); // use headless display to prevent image crashing/becoming unresponsive
require("./vm.input.js");
require("./vm.input.headless.js"); // use headless input to prevent image crashing/becoming unresponsive
require("./vm.plugins.js");
require("./vm.plugins.file.node");
// Set the appropriate VM and platform values
Object.extend(Squeak, {
vmPath: process.cwd() + path.sep,
platformSubtype: "Node.js",
osVersion: process.version + " " + os.platform() + " " + os.release() + " " + os.arch(),
windowSystem: "none",
});
// Extend the Squeak primitives with ability to load modules dynamically
Object.extend(Squeak.Primitives.prototype, {
loadModuleDynamically: function(modName) {
try {
require("./plugins/" + modName);
// Modules register themselves, should be available now
return Squeak.externalModules[modName];
} catch(e) {
console.error("Plugin " + modName + " could not be loaded");
}
return undefined;
}
});
// Read raw image
fs.readFile(root + imageName + ".image", function(error, data) {
if (error) {
console.error("Failed to read image", error);
return;
}
// Create Squeak image from raw data
var image = new Squeak.Image(root + imageName);
image.readFromBuffer(data.buffer, function startRunning() {
// Create fake display and create interpreter
var display = { vmOptions: [ "-vm-display-null", "-nodisplay" ] };
var vm = new Squeak.Interpreter(image, display);
function run() {
try {
vm.interpret(200, function runAgain(ms) {
// Ignore display.quitFlag when requested.
// Some Smalltalk images quit when no display is found.
if (ignoreQuit || !display.quitFlag) {
setTimeout(run, ms === "sleep" ? 10 : ms);
}
});
} catch(e) {
console.error("Failure during Squeak run: ", e);
}
}
// Start the interpreter
run();
});
});
|