worker: convert globals to FileWorkingStore and Builder classes, emscripten types

This commit is contained in:
Steven Hugg 2021-07-30 18:21:50 -05:00
parent 29f0238b90
commit 34322dd3d7
3 changed files with 246 additions and 176 deletions

11
package-lock.json generated
View File

@ -9,6 +9,7 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@sentry/electron": "^2.5.1", "@sentry/electron": "^2.5.1",
"@types/emscripten": "^1.39.5",
"@wasmer/wasi": "^0.12.0", "@wasmer/wasi": "^0.12.0",
"@wasmer/wasmfs": "^0.12.0", "@wasmer/wasmfs": "^0.12.0",
"binaryen": "^101.0.0", "binaryen": "^101.0.0",
@ -653,6 +654,11 @@
"integrity": "sha512-7fDOJFA/x8B+sO1901BmHlf5dE1cxBU8mRXj8QOEDnn16hhGJv/IHxJtZhvsabZsIMn0eLIyeOKAeqSNJJYTpA==", "integrity": "sha512-7fDOJFA/x8B+sO1901BmHlf5dE1cxBU8mRXj8QOEDnn16hhGJv/IHxJtZhvsabZsIMn0eLIyeOKAeqSNJJYTpA==",
"dev": true "dev": true
}, },
"node_modules/@types/emscripten": {
"version": "1.39.5",
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.5.tgz",
"integrity": "sha512-DIOOg+POSrYl+OlNRHQuIEqCd8DCtynG57H862UCce16nXJX7J8eWxNGgOcf8Eyge8zXeSs27mz1UcFu8L/L7g=="
},
"node_modules/@types/escodegen": { "node_modules/@types/escodegen": {
"version": "0.0.6", "version": "0.0.6",
"integrity": "sha1-UjCpznluBCzabwhtvxnyLqMwZZw=", "integrity": "sha1-UjCpznluBCzabwhtvxnyLqMwZZw=",
@ -9656,6 +9662,11 @@
"integrity": "sha512-7fDOJFA/x8B+sO1901BmHlf5dE1cxBU8mRXj8QOEDnn16hhGJv/IHxJtZhvsabZsIMn0eLIyeOKAeqSNJJYTpA==", "integrity": "sha512-7fDOJFA/x8B+sO1901BmHlf5dE1cxBU8mRXj8QOEDnn16hhGJv/IHxJtZhvsabZsIMn0eLIyeOKAeqSNJJYTpA==",
"dev": true "dev": true
}, },
"@types/emscripten": {
"version": "1.39.5",
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.5.tgz",
"integrity": "sha512-DIOOg+POSrYl+OlNRHQuIEqCd8DCtynG57H862UCce16nXJX7J8eWxNGgOcf8Eyge8zXeSs27mz1UcFu8L/L7g=="
},
"@types/escodegen": { "@types/escodegen": {
"version": "0.0.6", "version": "0.0.6",
"integrity": "sha1-UjCpznluBCzabwhtvxnyLqMwZZw=", "integrity": "sha1-UjCpznluBCzabwhtvxnyLqMwZZw=",

View File

@ -11,6 +11,7 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@sentry/electron": "^2.5.1", "@sentry/electron": "^2.5.1",
"@types/emscripten": "^1.39.5",
"@wasmer/wasi": "^0.12.0", "@wasmer/wasi": "^0.12.0",
"@wasmer/wasmfs": "^0.12.0", "@wasmer/wasmfs": "^0.12.0",
"binaryen": "^101.0.0", "binaryen": "^101.0.0",

View File

@ -1,9 +1,14 @@
"use strict";
/// <reference types="emscripten" />
import type { WorkerResult, WorkerFileUpdate, WorkerBuildStep, WorkerMessage, WorkerError, Dependency, SourceLine, CodeListing, CodeListingMap, Segment, WorkerOutput, SourceLocation } from "../common/workertypes"; import type { WorkerResult, WorkerFileUpdate, WorkerBuildStep, WorkerMessage, WorkerError, Dependency, SourceLine, CodeListing, CodeListingMap, Segment, WorkerOutput, SourceLocation } from "../common/workertypes";
import { getBasePlatform, getRootBasePlatform, hex } from "../common/util"; import { getBasePlatform, getRootBasePlatform, hex } from "../common/util";
import { Assembler } from "./assembler"; import { Assembler } from "./assembler";
interface EmscriptenModule {
callMain: (args: string[]) => void;
FS : any; // TODO
}
declare function importScripts(path:string); declare function importScripts(path:string);
declare function postMessage(msg); declare function postMessage(msg);
@ -377,10 +382,160 @@ interface BuildStep extends WorkerBuildStep {
maxts? maxts?
}; };
var buildsteps : BuildStep[] = []; ///
var buildstartseq : number = 0;
var workfs : {[path:string]:FileEntry} = {}; class FileWorkingStore {
var workerseq : number = 0; workfs : {[path:string]:FileEntry} = {};
workerseq : number = 0;
constructor() {
this.reset();
}
reset() {
this.workfs = {};
this.newVersion();
}
currentVersion() {
return this.workerseq;
}
newVersion() {
let ts = new Date().getTime();
if (ts <= this.workerseq)
ts = ++this.workerseq;
return ts;
}
putFile(path:string, data:FileData) : FileEntry {
var encoding = (typeof data === 'string') ? 'utf8' : 'binary';
var entry = this.workfs[path];
if (!entry || !compareData(entry.data, data) || entry.encoding != encoding) {
this.workfs[path] = entry = {path:path, data:data, encoding:encoding, ts:this.newVersion()};
console.log('+++', entry.path, entry.encoding, entry.data.length, entry.ts);
}
return entry;
}
hasFile(path: string) {
return this.workfs[path] != null;
}
getFileData(path:string) : FileData {
return this.workfs[path] && this.workfs[path].data;
}
getFileAsString(path:string) : string {
let data = this.getFileData(path);
if (data != null && typeof data !== 'string')
throw new Error(`${path}: expected string`)
return data as string; // TODO
}
getFileEntry(path:string) : FileEntry {
return this.workfs[path];
}
}
var store = new FileWorkingStore();
///
class Builder {
steps : BuildStep[] = [];
startseq : number = 0;
// returns true if file changed during this build step
wasChanged(entry:FileEntry) : boolean {
return entry.ts > this.startseq;
}
executeBuildSteps() {
this.startseq = store.currentVersion();
var linkstep : BuildStep = null;
while (this.steps.length) {
var step = this.steps.shift(); // get top of array
var platform = step.platform;
var toolfn = TOOLS[step.tool];
if (!toolfn) throw Error("no tool named " + step.tool);
step.params = PLATFORM_PARAMS[getBasePlatform(platform)];
try {
step.result = toolfn(step);
} catch (e) {
console.log("EXCEPTION", e, e.stack);
return {errors:[{line:0, msg:e+""}]}; // TODO: catch errors already generated?
}
if (step.result) {
step.result.params = step.params;
// errors? return them
if (step.result.errors && step.result.errors.length) {
applyDefaultErrorPath(step.result.errors, step.path);
return step.result;
}
// if we got some output, return it immediately
if (step.result.output) {
return step.result;
}
// combine files with a link tool?
if (step.result.linktool) {
if (linkstep) {
linkstep.files = linkstep.files.concat(step.result.files);
linkstep.args = linkstep.args.concat(step.result.args);
} else {
linkstep = {
tool:step.result.linktool,
platform:platform,
files:step.result.files,
args:step.result.args
};
}
}
// process with another tool?
if (step.result.nexttool) {
var asmstep : BuildStep = step.result;
asmstep.tool = step.result.nexttool;
asmstep.platform = platform;
this.steps.push(asmstep);
}
// process final step?
if (this.steps.length == 0 && linkstep) {
this.steps.push(linkstep);
linkstep = null;
}
}
}
}
handleMessage(data: WorkerMessage) : WorkerResult {
this.steps = [];
// file updates
if (data.updates) {
for (var i=0; i<data.updates.length; i++) {
var u = data.updates[i];
store.putFile(u.path, u.data);
}
}
// build steps
if (data.buildsteps) {
this.steps.push.apply(this.steps, data.buildsteps);
}
// single-file
if (data.code) {
this.steps.push(data);
}
// execute build steps
if (this.steps.length) {
var result = this.executeBuildSteps();
return result ? result : {unchanged:true};
}
// TODO: cache results
// message not recognized
console.log("Unknown message",data);
}
}
var builder = new Builder();
///
function applyDefaultErrorPath(errors:WorkerError[], path:string) {
if (!path) return;
for (var i=0; i<errors.length; i++) {
var err = errors[i];
if (!err.path && err.line) err.path = path;
}
}
function compareData(a:FileData, b:FileData) : boolean { function compareData(a:FileData, b:FileData) : boolean {
if (a.length != b.length) return false; if (a.length != b.length) return false;
@ -396,22 +551,11 @@ function compareData(a:FileData, b:FileData) : boolean {
} }
function putWorkFile(path:string, data:FileData) { function putWorkFile(path:string, data:FileData) {
var encoding = (typeof data === 'string') ? 'utf8' : 'binary'; return store.putFile(path, data);
var entry = workfs[path];
if (!entry || !compareData(entry.data, data) || entry.encoding != encoding) {
workfs[path] = entry = {path:path, data:data, encoding:encoding, ts:++workerseq};
console.log('+++', entry.path, entry.encoding, entry.data.length, entry.ts);
}
return entry;
}
// returns true if file changed during this build step
function wasChanged(entry:FileEntry) : boolean {
return entry.ts > buildstartseq;
} }
function getWorkFileAsString(path:string) : string { function getWorkFileAsString(path:string) : string {
return workfs[path] && workfs[path].data as string; // TODO return store.getFileAsString(path);
} }
function populateEntry(fs, path:string, entry:FileEntry, options:BuildOptions) { function populateEntry(fs, path:string, entry:FileEntry, options:BuildOptions) {
@ -429,17 +573,18 @@ function populateEntry(fs, path:string, entry:FileEntry, options:BuildOptions) {
} }
// write file // write file
fs.writeFile(path, data, {encoding:entry.encoding}); fs.writeFile(path, data, {encoding:entry.encoding});
fs.utime(path, entry.ts, entry.ts); var time = new Date(entry.ts);
fs.utime(path, time, time);
console.log("<<<", path, entry.data.length); console.log("<<<", path, entry.data.length);
} }
// can call multiple times (from populateFiles) // can call multiple times (from populateFiles)
function gatherFiles(step:BuildStep, options?:BuildOptions) { function gatherFiles(step:BuildStep, options?:BuildOptions) : number {
var maxts = 0; var maxts = 0;
if (step.files) { if (step.files) {
for (var i=0; i<step.files.length; i++) { for (var i=0; i<step.files.length; i++) {
var path = step.files[i]; var path = step.files[i];
var entry = workfs[path]; var entry = store.workfs[path];
if (!entry) { if (!entry) {
throw new Error("No entry for path '" + path + "'"); throw new Error("No entry for path '" + path + "'");
} else { } else {
@ -458,7 +603,7 @@ function gatherFiles(step:BuildStep, options?:BuildOptions) {
} }
else if (step.path) { else if (step.path) {
var path = step.path; var path = step.path;
var entry = workfs[path]; var entry = store.workfs[path];
maxts = entry.ts; maxts = entry.ts;
step.files = [path]; step.files = [path];
} }
@ -479,7 +624,7 @@ function populateFiles(step:BuildStep, fs, options?:BuildOptions) {
if (!step.files) throw Error("call gatherFiles() first"); if (!step.files) throw Error("call gatherFiles() first");
for (var i=0; i<step.files.length; i++) { for (var i=0; i<step.files.length; i++) {
var path = step.files[i]; var path = step.files[i];
populateEntry(fs, path, workfs[path], options); populateEntry(fs, path, store.workfs[path], options);
} }
} }
@ -488,8 +633,8 @@ function populateExtraFiles(step:BuildStep, fs, extrafiles) {
for (var i=0; i<extrafiles.length; i++) { for (var i=0; i<extrafiles.length; i++) {
var xfn = extrafiles[i]; var xfn = extrafiles[i];
// is this file cached? // is this file cached?
if (workfs[xfn]) { if (store.workfs[xfn]) {
fs.writeFile(xfn, workfs[xfn].data, {encoding:'binary'}); fs.writeFile(xfn, store.workfs[xfn].data, {encoding:'binary'});
continue; continue;
} }
// fetch from network // fetch from network
@ -514,7 +659,7 @@ function staleFiles(step:BuildStep, targets:string[]) {
if (!step.maxts) throw Error("call populateFiles() first"); if (!step.maxts) throw Error("call populateFiles() first");
// see if any target files are more recent than inputs // see if any target files are more recent than inputs
for (var i=0; i<targets.length; i++) { for (var i=0; i<targets.length; i++) {
var entry = workfs[targets[i]]; var entry = store.workfs[targets[i]];
if (!entry || step.maxts > entry.ts) if (!entry || step.maxts > entry.ts)
return true; return true;
} }
@ -526,7 +671,7 @@ function anyTargetChanged(step:BuildStep, targets:string[]) {
if (!step.maxts) throw Error("call populateFiles() first"); if (!step.maxts) throw Error("call populateFiles() first");
// see if any target files are more recent than inputs // see if any target files are more recent than inputs
for (var i=0; i<targets.length; i++) { for (var i=0; i<targets.length; i++) {
var entry = workfs[targets[i]]; var entry = store.workfs[targets[i]];
if (!entry || entry.ts > step.maxts) if (!entry || entry.ts > step.maxts)
return true; return true;
} }
@ -883,11 +1028,11 @@ function assembleDASM(step:BuildStep) {
errorMatcher(s); errorMatcher(s);
} }
} }
var Module = emglobal.DASM({ var Module : EmscriptenModule = emglobal.DASM({
noInitialRun:true, noInitialRun:true,
print:match_fn print:match_fn
}); });
var FS = Module['FS']; var FS = Module.FS;
populateFiles(step, FS, { populateFiles(step, FS, {
mainFilePath:'main.a' mainFilePath:'main.a'
}); });
@ -1056,14 +1201,14 @@ function assembleCA65(step:BuildStep) {
var lstpath = step.prefix+".lst"; var lstpath = step.prefix+".lst";
if (staleFiles(step, [objpath, lstpath])) { if (staleFiles(step, [objpath, lstpath])) {
var objout, lstout; var objout, lstout;
var CA65 = emglobal.ca65({ var CA65 : EmscriptenModule = emglobal.ca65({
instantiateWasm: moduleInstFn('ca65'), instantiateWasm: moduleInstFn('ca65'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:msvcErrorMatcher(errors), printErr:msvcErrorMatcher(errors),
}); });
var FS = CA65['FS']; var FS = CA65.FS;
setupFS(FS, '65-'+getRootBasePlatform(step.platform)); setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
fixParamsWithDefines(step.path, step.params); fixParamsWithDefines(step.path, step.params);
@ -1094,20 +1239,20 @@ function linkLD65(step:BuildStep) {
var binpath = "main"; var binpath = "main";
if (staleFiles(step, [binpath])) { if (staleFiles(step, [binpath])) {
var errors = []; var errors = [];
var LD65 = emglobal.ld65({ var LD65 : EmscriptenModule = emglobal.ld65({
instantiateWasm: moduleInstFn('ld65'), instantiateWasm: moduleInstFn('ld65'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:function(s) { errors.push({msg:s,line:0}); } printErr:function(s) { errors.push({msg:s,line:0}); }
}); });
var FS = LD65['FS']; var FS = LD65.FS;
setupFS(FS, '65-'+getRootBasePlatform(step.platform)); setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_link_files); populateExtraFiles(step, FS, params.extra_link_files);
// populate .cfg file, if it is a custom one // populate .cfg file, if it is a custom one
if (workfs[params.cfgfile]) { if (store.hasFile(params.cfgfile)) {
populateEntry(FS, params.cfgfile, workfs[params.cfgfile], null); populateEntry(FS, params.cfgfile, store.getFileEntry(params.cfgfile), null);
} }
var libargs = params.libargs || []; var libargs = params.libargs || [];
var cfgfile = params.cfgfile; var cfgfile = params.cfgfile;
@ -1257,14 +1402,14 @@ function compileCC65(step:BuildStep) {
gatherFiles(step, {mainFilePath:"main.c"}); gatherFiles(step, {mainFilePath:"main.c"});
var destpath = step.prefix + '.s'; var destpath = step.prefix + '.s';
if (staleFiles(step, [destpath])) { if (staleFiles(step, [destpath])) {
var CC65 = emglobal.cc65({ var CC65 : EmscriptenModule = emglobal.cc65({
instantiateWasm: moduleInstFn('cc65'), instantiateWasm: moduleInstFn('cc65'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:match_fn, printErr:match_fn,
}); });
var FS = CC65['FS']; var FS = CC65.FS;
setupFS(FS, '65-'+getRootBasePlatform(step.platform)); setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
fixParamsWithDefines(step.path, params); fixParamsWithDefines(step.path, params);
@ -1368,14 +1513,14 @@ function assembleSDASZ80(step:BuildStep) {
} }
} }
} }
var ASZ80 = emglobal.sdasz80({ var ASZ80 : EmscriptenModule = emglobal.sdasz80({
instantiateWasm: moduleInstFn('sdasz80'), instantiateWasm: moduleInstFn('sdasz80'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:match_asm_fn, print:match_asm_fn,
printErr:match_asm_fn, printErr:match_asm_fn,
}); });
var FS = ASZ80['FS']; var FS = ASZ80.FS;
populateFiles(step, FS); populateFiles(step, FS);
execMain(step, ASZ80, ['-plosgffwy', step.path]); execMain(step, ASZ80, ['-plosgffwy', step.path]);
if (errors.length) { if (errors.length) {
@ -1413,14 +1558,14 @@ function linkSDLDZ80(step:BuildStep)
} }
} }
var params = step.params; var params = step.params;
var LDZ80 = emglobal.sdldz80({ var LDZ80 : EmscriptenModule = emglobal.sdldz80({
instantiateWasm: moduleInstFn('sdldz80'), instantiateWasm: moduleInstFn('sdldz80'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:match_aslink_fn, print:match_aslink_fn,
printErr:match_aslink_fn, printErr:match_aslink_fn,
}); });
var FS = LDZ80['FS']; var FS = LDZ80.FS;
setupFS(FS, 'sdcc'); setupFS(FS, 'sdcc');
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_link_files); populateExtraFiles(step, FS, params.extra_link_files);
@ -1517,7 +1662,7 @@ function compileSDCC(step:BuildStep) {
var errors = []; var errors = [];
var params = step.params; var params = step.params;
loadNative('sdcc'); loadNative('sdcc');
var SDCC = emglobal.sdcc({ var SDCC : EmscriptenModule = emglobal.sdcc({
instantiateWasm: moduleInstFn('sdcc'), instantiateWasm: moduleInstFn('sdcc'),
noInitialRun:true, noInitialRun:true,
noFSInit:true, noFSInit:true,
@ -1525,7 +1670,7 @@ function compileSDCC(step:BuildStep) {
printErr:msvcErrorMatcher(errors), printErr:msvcErrorMatcher(errors),
//TOTAL_MEMORY:256*1024*1024, //TOTAL_MEMORY:256*1024*1024,
}); });
var FS = SDCC['FS']; var FS = SDCC.FS;
populateFiles(step, FS); populateFiles(step, FS);
// load source file and preprocess // load source file and preprocess
var code = getWorkFileAsString(step.path); var code = getWorkFileAsString(step.path);
@ -1595,13 +1740,13 @@ function preprocessMCPP(step:BuildStep, filesys:string) {
// <stdin>:2: error: Can't open include file "foo.h" // <stdin>:2: error: Can't open include file "foo.h"
var errors = []; var errors = [];
var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2, step.path); var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2, step.path);
var MCPP = emglobal.mcpp({ var MCPP : EmscriptenModule = emglobal.mcpp({
noInitialRun:true, noInitialRun:true,
noFSInit:true, noFSInit:true,
print:print_fn, print:print_fn,
printErr:match_fn, printErr:match_fn,
}); });
var FS = MCPP['FS']; var FS = MCPP.FS;
if (filesys) setupFS(FS, filesys); if (filesys) setupFS(FS, filesys);
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_compile_files); populateExtraFiles(step, FS, params.extra_compile_files);
@ -1619,7 +1764,7 @@ function preprocessMCPP(step:BuildStep, filesys:string) {
if (params.extra_preproc_args) { if (params.extra_preproc_args) {
args.push.apply(args, params.extra_preproc_args); args.push.apply(args, params.extra_preproc_args);
} }
MCPP.callMain(args); execMain(step, MCPP, args);
if (errors.length) if (errors.length)
return {errors:errors}; return {errors:errors};
var iout = FS.readFile("main.i", {encoding:'utf8'}); var iout = FS.readFile("main.i", {encoding:'utf8'});
@ -1766,7 +1911,7 @@ function compileVerilator(step:BuildStep) {
// TODO: %Error: Specified --top-module 'ALU' isn't at the top level, it's under another cell 'cpu' // TODO: %Error: Specified --top-module 'ALU' isn't at the top level, it's under another cell 'cpu'
// TODO: ... Use "/* verilator lint_off BLKSEQ */" and lint_on around source to disable this message. // TODO: ... Use "/* verilator lint_off BLKSEQ */" and lint_on around source to disable this message.
var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?):(\d+)?[:]?\s*(.+)/i, 3, 4, step.path, 2); var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?):(\d+)?[:]?\s*(.+)/i, 3, 4, step.path, 2);
var verilator_mod = emglobal.verilator_bin({ var verilator_mod : EmscriptenModule = emglobal.verilator_bin({
instantiateWasm: moduleInstFn('verilator_bin'), instantiateWasm: moduleInstFn('verilator_bin'),
noInitialRun: true, noInitialRun: true,
noExitRuntime: true, noExitRuntime: true,
@ -1777,7 +1922,7 @@ function compileVerilator(step:BuildStep) {
}); });
var code = getWorkFileAsString(step.path); var code = getWorkFileAsString(step.path);
var topmod = detectTopModuleName(code); var topmod = detectTopModuleName(code);
var FS = verilator_mod['FS']; var FS = verilator_mod.FS;
var listings : CodeListingMap = {}; var listings : CodeListingMap = {};
// process inline assembly, add listings where found // process inline assembly, add listings where found
populateFiles(step, FS, { populateFiles(step, FS, {
@ -1803,7 +1948,7 @@ function compileVerilator(step:BuildStep) {
"--x-assign", "fast", "--noassert", "--pins-sc-biguint", "--x-assign", "fast", "--noassert", "--pins-sc-biguint",
"--debug-check", // for XML output "--debug-check", // for XML output
"--top-module", topmod, step.path] "--top-module", topmod, step.path]
verilator_mod.callMain(args); execMain(step, verilator_mod, args);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
errors.push({line:0,msg:"Compiler internal error: " + e}); errors.push({line:0,msg:"Compiler internal error: " + e});
@ -1853,7 +1998,7 @@ function compileYosys(step:BuildStep) {
var errors = []; var errors = [];
var match_fn = makeErrorMatcher(errors, /ERROR: (.+?) in line (.+?[.]v):(\d+)[: ]+(.+)/i, 3, 4, step.path); var match_fn = makeErrorMatcher(errors, /ERROR: (.+?) in line (.+?[.]v):(\d+)[: ]+(.+)/i, 3, 4, step.path);
starttime(); starttime();
var yosys_mod = emglobal.yosys({ var yosys_mod : EmscriptenModule = emglobal.yosys({
instantiateWasm: moduleInstFn('yosys'), instantiateWasm: moduleInstFn('yosys'),
noInitialRun:true, noInitialRun:true,
print:print_fn, print:print_fn,
@ -1861,11 +2006,11 @@ function compileYosys(step:BuildStep) {
}); });
endtime("create module"); endtime("create module");
var topmod = detectTopModuleName(code); var topmod = detectTopModuleName(code);
var FS = yosys_mod['FS']; var FS = yosys_mod.FS;
FS.writeFile(topmod+".v", code); FS.writeFile(topmod+".v", code);
starttime(); starttime();
try { try {
yosys_mod.callMain(["-q", "-o", topmod+".json", "-S", topmod+".v"]); execMain(step, yosys_mod, ["-q", "-o", topmod+".json", "-S", topmod+".v"]);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
endtime("compile"); endtime("compile");
@ -1902,14 +2047,14 @@ error1.asm(11): warning: 'foobar' treated as label (instruction typo?)
Add a colon or move to first column to stop this warning. Add a colon or move to first column to stop this warning.
1 errors (see listing if no diagnostics appeared here) 1 errors (see listing if no diagnostics appeared here)
*/ */
var ZMAC = emglobal.zmac({ var ZMAC : EmscriptenModule = emglobal.zmac({
instantiateWasm: moduleInstFn('zmac'), instantiateWasm: moduleInstFn('zmac'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:makeErrorMatcher(errors, /([^( ]+)\s*[(](\d+)[)]\s*:\s*(.+)/, 2, 3, step.path), printErr:makeErrorMatcher(errors, /([^( ]+)\s*[(](\d+)[)]\s*:\s*(.+)/, 2, 3, step.path),
}); });
var FS = ZMAC['FS']; var FS = ZMAC.FS;
populateFiles(step, FS); populateFiles(step, FS);
// TODO: don't know why CIM (hexary) doesn't work // TODO: don't know why CIM (hexary) doesn't work
execMain(step, ZMAC, ['-z', '-c', '--oo', 'lst,cim', step.path]); execMain(step, ZMAC, ['-z', '-c', '--oo', 'lst,cim', step.path]);
@ -1954,14 +2099,14 @@ function preprocessBatariBasic(code:string) : string {
bbout += s; bbout += s;
bbout += "\n"; bbout += "\n";
} }
var BBPRE = emglobal.preprocess({ var BBPRE : EmscriptenModule = emglobal.preprocess({
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:addbbout_fn, print:addbbout_fn,
printErr:print_fn, printErr:print_fn,
noFSInit:true, noFSInit:true,
}); });
var FS = BBPRE['FS']; var FS = BBPRE.FS;
setupStdin(FS, code); setupStdin(FS, code);
BBPRE.callMain([]); BBPRE.callMain([]);
console.log("preprocess " + code.length + " -> " + bbout.length + " bytes"); console.log("preprocess " + code.length + " -> " + bbout.length + " bytes");
@ -1995,7 +2140,7 @@ function compileBatariBasic(step:BuildStep) {
gatherFiles(step, {mainFilePath:"main.bas"}); gatherFiles(step, {mainFilePath:"main.bas"});
var destpath = step.prefix + '.asm'; var destpath = step.prefix + '.asm';
if (staleFiles(step, [destpath])) { if (staleFiles(step, [destpath])) {
var BB = emglobal.bb2600basic({ var BB : EmscriptenModule = emglobal.bb2600basic({
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:addasmout_fn, print:addasmout_fn,
@ -2003,7 +2148,7 @@ function compileBatariBasic(step:BuildStep) {
noFSInit:true, noFSInit:true,
TOTAL_MEMORY:64*1024*1024, TOTAL_MEMORY:64*1024*1024,
}); });
var FS = BB['FS']; var FS = BB.FS;
populateFiles(step, FS); populateFiles(step, FS);
// preprocess, pipe file to stdin // preprocess, pipe file to stdin
var code = getWorkFileAsString(step.path); var code = getWorkFileAsString(step.path);
@ -2097,20 +2242,20 @@ function assembleXASM6809(step:BuildStep) {
lasterror = s.slice(6); lasterror = s.slice(6);
} }
} }
var Module = emglobal.xasm6809({ var Module : EmscriptenModule = emglobal.xasm6809({
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:match_fn, print:match_fn,
printErr:print_fn printErr:print_fn
}); });
var FS = Module['FS']; var FS = Module.FS;
//setupFS(FS); //setupFS(FS);
populateFiles(step, FS, { populateFiles(step, FS, {
mainFilePath:'main.asm' mainFilePath:'main.asm'
}); });
var binpath = step.prefix + '.bin'; var binpath = step.prefix + '.bin';
var lstpath = step.prefix + '.lst'; // in stdout var lstpath = step.prefix + '.lst'; // in stdout
Module.callMain(["-c", "-l", "-s", "-y", "-o="+binpath, step.path]); execMain(step, Module, ["-c", "-l", "-s", "-y", "-o="+binpath, step.path]);
if (errors.length) if (errors.length)
return {errors:errors}; return {errors:errors};
var aout = FS.readFile(binpath, {encoding:'binary'}); var aout = FS.readFile(binpath, {encoding:'binary'});
@ -2170,12 +2315,12 @@ function assembleNESASM(step:BuildStep) {
break; break;
} }
} }
var Module = emglobal.nesasm({ var Module : EmscriptenModule = emglobal.nesasm({
instantiateWasm: moduleInstFn('nesasm'), instantiateWasm: moduleInstFn('nesasm'),
noInitialRun:true, noInitialRun:true,
print:match_fn print:match_fn
}); });
var FS = Module['FS']; var FS = Module.FS;
populateFiles(step, FS, { populateFiles(step, FS, {
mainFilePath:'main.a' mainFilePath:'main.a'
}); });
@ -2260,7 +2405,7 @@ function compileCMOC(step:BuildStep) {
'-I/share/include', '-I/share/include',
'-I.', '-I.',
step.path]; step.path];
var CMOC = emglobal.cmoc({ var CMOC : EmscriptenModule = emglobal.cmoc({
instantiateWasm: moduleInstFn('cmoc'), instantiateWasm: moduleInstFn('cmoc'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
@ -2273,7 +2418,7 @@ function compileCMOC(step:BuildStep) {
if (preproc.errors) return preproc; if (preproc.errors) return preproc;
else code = preproc.code; else code = preproc.code;
// set up filesystem // set up filesystem
var FS = CMOC['FS']; var FS = CMOC.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform)); //setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
FS.writeFile(step.path, code); FS.writeFile(step.path, code);
@ -2304,14 +2449,14 @@ function assembleLWASM(step:BuildStep) {
if (staleFiles(step, [objpath, lstpath])) { if (staleFiles(step, [objpath, lstpath])) {
var objout, lstout; var objout, lstout;
var args = ['-9', '--obj', '-I/share/asminc', '-o'+objpath, '-l'+lstpath, step.path]; var args = ['-9', '--obj', '-I/share/asminc', '-o'+objpath, '-l'+lstpath, step.path];
var LWASM = emglobal.lwasm({ var LWASM : EmscriptenModule = emglobal.lwasm({
instantiateWasm: moduleInstFn('lwasm'), instantiateWasm: moduleInstFn('lwasm'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:msvcErrorMatcher(errors), printErr:msvcErrorMatcher(errors),
}); });
var FS = LWASM['FS']; var FS = LWASM.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform)); //setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
fixParamsWithDefines(step.path, step.params); fixParamsWithDefines(step.path, step.params);
@ -2337,7 +2482,7 @@ function linkLWLINK(step:BuildStep) {
var binpath = "main"; var binpath = "main";
if (staleFiles(step, [binpath])) { if (staleFiles(step, [binpath])) {
var errors = []; var errors = [];
var LWLINK = emglobal.lwlink({ var LWLINK : EmscriptenModule = emglobal.lwlink({
instantiateWasm: moduleInstFn('lwlink'), instantiateWasm: moduleInstFn('lwlink'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
@ -2349,7 +2494,7 @@ function linkLWLINK(step:BuildStep) {
errors.push({msg:s,line:0}); errors.push({msg:s,line:0});
} }
}); });
var FS = LWLINK['FS']; var FS = LWLINK.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform)); //setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_link_files); populateExtraFiles(step, FS, params.extra_link_files);
@ -2449,7 +2594,7 @@ function compileSmallerC(step:BuildStep) {
//'-nobss', //'-nobss',
'-no-externs', '-no-externs',
step.path, destpath]; step.path, destpath];
var smlrc = emglobal.smlrc({ var smlrc : EmscriptenModule = emglobal.smlrc({
instantiateWasm: moduleInstFn('smlrc'), instantiateWasm: moduleInstFn('smlrc'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
@ -2462,7 +2607,7 @@ function compileSmallerC(step:BuildStep) {
if (preproc.errors) return preproc; if (preproc.errors) return preproc;
else code = preproc.code; else code = preproc.code;
// set up filesystem // set up filesystem
var FS = smlrc['FS']; var FS = smlrc.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform)); //setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
FS.writeFile(step.path, code); FS.writeFile(step.path, code);
@ -2499,14 +2644,14 @@ function assembleYASM(step:BuildStep) {
'-o', objpath, '-l', lstpath, '--mapfile='+mappath, '-o', objpath, '-l', lstpath, '--mapfile='+mappath,
step.path]; step.path];
// return yasm/*.ready*/ // return yasm/*.ready*/
var YASM = emglobal.yasm({ var YASM : EmscriptenModule = emglobal.yasm({
instantiateWasm: moduleInstFn('yasm'), instantiateWasm: moduleInstFn('yasm'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:print_fn, print:print_fn,
printErr:msvcErrorMatcher(errors), printErr:msvcErrorMatcher(errors),
}); });
var FS = YASM['FS']; var FS = YASM.FS;
//setupFS(FS, '65-'+getRootBasePlatform(step.platform)); //setupFS(FS, '65-'+getRootBasePlatform(step.platform));
populateFiles(step, FS); populateFiles(step, FS);
//fixParamsWithDefines(step.path, step.params); //fixParamsWithDefines(step.path, step.params);
@ -2581,14 +2726,14 @@ function compileInform6(step:BuildStep) {
} }
} }
var args = [ '-afjnops', '-v5', '-Cu', '-E1', '-k', '+/share/lib', step.path ]; var args = [ '-afjnops', '-v5', '-Cu', '-E1', '-k', '+/share/lib', step.path ];
var inform = emglobal.inform({ var inform : EmscriptenModule = emglobal.inform({
instantiateWasm: moduleInstFn('inform'), instantiateWasm: moduleInstFn('inform'),
noInitialRun:true, noInitialRun:true,
//logReadFiles:true, //logReadFiles:true,
print:match_fn, print:match_fn,
printErr:match_fn, printErr:match_fn,
}); });
var FS = inform['FS']; var FS = inform.FS;
setupFS(FS, 'inform'); setupFS(FS, 'inform');
populateFiles(step, FS); populateFiles(step, FS);
//fixParamsWithDefines(step.path, step.params); //fixParamsWithDefines(step.path, step.params);
@ -2675,7 +2820,7 @@ function assembleMerlin32(step:BuildStep) {
var objpath = step.prefix+".bin"; var objpath = step.prefix+".bin";
if (staleFiles(step, [objpath])) { if (staleFiles(step, [objpath])) {
var args = [ '-v', step.path ]; var args = [ '-v', step.path ];
var merlin32 = emglobal.merlin32({ var merlin32 : EmscriptenModule = emglobal.merlin32({
instantiateWasm: moduleInstFn('merlin32'), instantiateWasm: moduleInstFn('merlin32'),
noInitialRun:true, noInitialRun:true,
print:(s:string) => { print:(s:string) => {
@ -2697,7 +2842,7 @@ function assembleMerlin32(step:BuildStep) {
}, },
printErr:print_fn, printErr:print_fn,
}); });
var FS = merlin32['FS']; var FS = merlin32.FS;
populateFiles(step, FS); populateFiles(step, FS);
execMain(step, merlin32, args); execMain(step, merlin32, args);
if (errors.length) if (errors.length)
@ -2761,13 +2906,13 @@ function compileFastBasic(step:BuildStep) {
var destpath = step.prefix + '.s'; var destpath = step.prefix + '.s';
var errors = []; var errors = [];
if (staleFiles(step, [destpath])) { if (staleFiles(step, [destpath])) {
var fastbasic = emglobal.fastbasic({ var fastbasic : EmscriptenModule = emglobal.fastbasic({
instantiateWasm: moduleInstFn('fastbasic-int'), instantiateWasm: moduleInstFn('fastbasic-int'),
noInitialRun:true, noInitialRun:true,
print:print_fn, print:print_fn,
printErr:makeErrorMatcher(errors, /(.+?):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1), printErr:makeErrorMatcher(errors, /(.+?):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1),
}); });
var FS = fastbasic['FS']; var FS = fastbasic.FS;
populateFiles(step, FS); populateFiles(step, FS);
var libfile = 'fastbasic-int.lib' var libfile = 'fastbasic-int.lib'
params.libargs = [libfile]; params.libargs = [libfile];
@ -2847,13 +2992,13 @@ function compileSilice(step:BuildStep) {
} }
else console.log(s); else console.log(s);
} }
var silice = emglobal.silice({ var silice : EmscriptenModule = emglobal.silice({
instantiateWasm: moduleInstFn('silice'), instantiateWasm: moduleInstFn('silice'),
noInitialRun:true, noInitialRun:true,
print:match_fn, print:match_fn,
printErr:match_fn, printErr:match_fn,
}); });
var FS = silice['FS']; var FS = silice.FS;
setupFS(FS, 'Silice'); setupFS(FS, 'Silice');
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_compile_files); populateExtraFiles(step, FS, params.extra_compile_files);
@ -2885,14 +3030,14 @@ function compileWiz(step:BuildStep) {
var destpath = step.prefix + (params.wiz_rom_ext || ".bin"); var destpath = step.prefix + (params.wiz_rom_ext || ".bin");
var errors : WorkerError[] = []; var errors : WorkerError[] = [];
if (staleFiles(step, [destpath])) { if (staleFiles(step, [destpath])) {
var wiz = emglobal.wiz({ var wiz : EmscriptenModule = emglobal.wiz({
instantiateWasm: moduleInstFn('wiz'), instantiateWasm: moduleInstFn('wiz'),
noInitialRun:true, noInitialRun:true,
print:print_fn, print:print_fn,
//test.wiz:2: error: expected statement, but got identifier `test` //test.wiz:2: error: expected statement, but got identifier `test`
printErr:makeErrorMatcher(errors, /(.+?):(\d+):\s*(.+)/, 2, 3, step.path, 1), printErr:makeErrorMatcher(errors, /(.+?):(\d+):\s*(.+)/, 2, 3, step.path, 1),
}); });
var FS = wiz['FS']; var FS = wiz.FS;
setupFS(FS, 'wiz'); setupFS(FS, 'wiz');
populateFiles(step, FS); populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_compile_files); populateExtraFiles(step, FS, params.extra_compile_files);
@ -2941,14 +3086,14 @@ function assembleARMIPS(step:BuildStep) {
if (staleFiles(step, [objpath])) { if (staleFiles(step, [objpath])) {
var args = [ step.path, '-temp', lstpath, '-sym', sympath, '-erroronwarning' ]; var args = [ step.path, '-temp', lstpath, '-sym', sympath, '-erroronwarning' ];
var armips = emglobal.armips({ var armips : EmscriptenModule = emglobal.armips({
instantiateWasm: moduleInstFn('armips'), instantiateWasm: moduleInstFn('armips'),
noInitialRun:true, noInitialRun:true,
print:error_fn, print:error_fn,
printErr:error_fn, printErr:error_fn,
}); });
var FS = armips['FS']; var FS = armips.FS;
var code = getWorkFileAsString(step.path); var code = getWorkFileAsString(step.path);
code = `.arm.little :: .create "${objpath}",0 :: ${code} code = `.arm.little :: .create "${objpath}",0 :: ${code}
.close`; .close`;
@ -3073,14 +3218,14 @@ function assembleVASMARM(step:BuildStep) {
if (staleFiles(step, [objpath])) { if (staleFiles(step, [objpath])) {
var args = [ '-Fbin', '-m7tdmi', '-x', '-wfail', step.path, '-o', objpath, '-L', lstpath ]; var args = [ '-Fbin', '-m7tdmi', '-x', '-wfail', step.path, '-o', objpath, '-L', lstpath ];
var vasm = emglobal.vasm({ var vasm : EmscriptenModule = emglobal.vasm({
instantiateWasm: moduleInstFn('vasmarm_std'), instantiateWasm: moduleInstFn('vasmarm_std'),
noInitialRun:true, noInitialRun:true,
print:match_fn, print:match_fn,
printErr:match_fn, printErr:match_fn,
}); });
var FS = vasm['FS']; var FS = vasm.FS;
populateFiles(step, FS); populateFiles(step, FS);
execMain(step, vasm, args); execMain(step, vasm, args);
if (errors.length) { if (errors.length) {
@ -3228,70 +3373,6 @@ var TOOL_PRELOADFS = {
'wiz': 'wiz', 'wiz': 'wiz',
} }
function applyDefaultErrorPath(errors:WorkerError[], path:string) {
if (!path) return;
for (var i=0; i<errors.length; i++) {
var err = errors[i];
if (!err.path && err.line) err.path = path;
}
}
function executeBuildSteps() {
buildstartseq = workerseq;
var linkstep : BuildStep = null;
while (buildsteps.length) {
var step = buildsteps.shift(); // get top of array
var platform = step.platform;
var toolfn = TOOLS[step.tool];
if (!toolfn) throw Error("no tool named " + step.tool);
step.params = PLATFORM_PARAMS[getBasePlatform(platform)];
try {
step.result = toolfn(step);
} catch (e) {
console.log("EXCEPTION", e, e.stack);
return {errors:[{line:0, msg:e+""}]}; // TODO: catch errors already generated?
}
if (step.result) {
step.result.params = step.params;
// errors? return them
if (step.result.errors && step.result.errors.length) {
applyDefaultErrorPath(step.result.errors, step.path);
return step.result;
}
// if we got some output, return it immediately
if (step.result.output) {
return step.result;
}
// combine files with a link tool?
if (step.result.linktool) {
if (linkstep) {
linkstep.files = linkstep.files.concat(step.result.files);
linkstep.args = linkstep.args.concat(step.result.args);
} else {
linkstep = {
tool:step.result.linktool,
platform:platform,
files:step.result.files,
args:step.result.args
};
}
}
// process with another tool?
if (step.result.nexttool) {
var asmstep : BuildStep = step.result;
asmstep.tool = step.result.nexttool;
asmstep.platform = platform;
buildsteps.push(asmstep);
}
// process final step?
if (buildsteps.length == 0 && linkstep) {
buildsteps.push(linkstep);
linkstep = null;
}
}
}
}
function handleMessage(data : WorkerMessage) : WorkerResult | {unchanged:true} { function handleMessage(data : WorkerMessage) : WorkerResult | {unchanged:true} {
// preload file system // preload file system
if (data.preload) { if (data.preload) {
@ -3306,33 +3387,10 @@ function handleMessage(data : WorkerMessage) : WorkerResult | {unchanged:true} {
} }
// clear filesystem? (TODO: buildkey) // clear filesystem? (TODO: buildkey)
if (data.reset) { if (data.reset) {
workfs = {}; store.reset();
return; return;
} }
buildsteps = []; return builder.handleMessage(data);
// file updates
if (data.updates) {
for (var i=0; i<data.updates.length; i++) {
var u = data.updates[i];
putWorkFile(u.path, u.data);
}
}
// build steps
if (data.buildsteps) {
buildsteps.push.apply(buildsteps, data.buildsteps);
}
// single-file
if (data.code) {
buildsteps.push(data);
}
// execute build steps
if (buildsteps.length) {
var result = executeBuildSteps();
return result ? result : {unchanged:true};
}
// TODO: cache results
// message not recognized
console.log("Unknown message",data);
} }
if (ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) {