8bitworkshop/src/worker/tools/misc.ts

194 lines
7.8 KiB
TypeScript

import { Segment, CodeListingMap, WorkerResult, WorkerError } from "../../common/workertypes";
import * as basic_compiler from '../../common/basic/compiler';
import { getRootBasePlatform, parseXMLPoorly } from "../../common/util";
import { EmscriptenModule, emglobal, execMain, load, loadNative, moduleInstFn, print_fn, setupFS } from "../wasmutils";
import { BuildStep, BuildStepResult, getWorkFileAsString, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, populateExtraFiles } from "../builder";
import { msvcErrorMatcher, parseListing, makeErrorMatcher } from "../listingutils";
import { setupRequireFunction } from "../workermain";
export function translateShowdown(step: BuildStep): BuildStepResult {
setupRequireFunction();
load("showdown.min");
var showdown = emglobal['showdown'];
var converter = new showdown.Converter({
tables: 'true',
smoothLivePreview: 'true',
requireSpaceBeforeHeadingText: 'true',
emoji: 'true',
});
var code = getWorkFileAsString(step.path);
var html = converter.makeHtml(code);
delete emglobal['require'];
return {
output: html
};
}
export function compileInform6(step: BuildStep): BuildStepResult {
loadNative("inform");
var errors = [];
gatherFiles(step, { mainFilePath: "main.inf" });
var objpath = step.prefix + ".z5";
if (staleFiles(step, [objpath])) {
var errorMatcher = msvcErrorMatcher(errors);
var lstout = "";
var match_fn = (s: string) => {
if (s.indexOf("Error:") >= 0) {
errorMatcher(s);
} else {
lstout += s;
lstout += "\n";
}
}
// TODO: step.path must end in '.inf' or error
var args = ['-afjnops', '-v5', '-Cu', '-E1', '-k', '+/share/lib', step.path];
var inform: EmscriptenModule = emglobal.inform({
instantiateWasm: moduleInstFn('inform'),
noInitialRun: true,
//logReadFiles:true,
print: match_fn,
printErr: match_fn,
});
var FS = inform.FS;
setupFS(FS, 'inform');
populateFiles(step, FS);
//fixParamsWithDefines(step.path, step.params);
execMain(step, inform, args);
if (errors.length)
return { errors: errors };
var objout = FS.readFile(objpath, { encoding: 'binary' });
putWorkFile(objpath, objout);
if (!anyTargetChanged(step, [objpath]))
return;
// parse debug XML
var symbolmap = {};
var segments: Segment[] = [];
var entitymap = {
// number -> string
'object': {}, 'property': {}, 'attribute': {}, 'constant': {}, 'global-variable': {}, 'routine': {},
};
var dbgout = FS.readFile("gameinfo.dbg", { encoding: 'utf8' });
var xmlroot = parseXMLPoorly(dbgout);
//console.log(xmlroot);
var segtype = "ram";
xmlroot.children.forEach((node) => {
switch (node.type) {
case 'global-variable':
case 'routine':
var ident = node.children.find((c, v) => c.type == 'identifier').text;
var address = parseInt(node.children.find((c, v) => c.type == 'address').text);
symbolmap[ident] = address;
entitymap[node.type][address] = ident;
break;
case 'object':
case 'property':
case 'attribute':
var ident = node.children.find((c, v) => c.type == 'identifier').text;
var value = parseInt(node.children.find((c, v) => c.type == 'value').text);
//entitymap[node.type][ident] = value;
entitymap[node.type][value] = ident;
//symbolmap[ident] = address | 0x1000000;
break;
case 'story-file-section':
var name = node.children.find((c, v) => c.type == 'type').text;
var address = parseInt(node.children.find((c, v) => c.type == 'address').text);
var endAddress = parseInt(node.children.find((c, v) => c.type == 'end-address').text);
if (name == "grammar table") segtype = "rom";
segments.push({ name: name, start: address, size: endAddress - address, type: segtype });
}
});
// parse listing
var listings: CodeListingMap = {};
// 35 +00015 <*> call_vs long_19 location long_424 -> sp
var lines = parseListing(lstout, /\s*(\d+)\s+[+]([0-9a-f]+)\s+([<*>]*)\s*(\w+)\s+(.+)/i, -1, 2, 4);
var lstpath = step.prefix + '.lst';
listings[lstpath] = { lines: [], asmlines: lines, text: lstout };
return {
output: objout, //.slice(0),
listings: listings,
errors: errors,
symbolmap: symbolmap,
segments: segments,
debuginfo: entitymap,
};
}
}
export function compileBASIC(step: BuildStep): WorkerResult {
var jsonpath = step.path + ".json";
gatherFiles(step);
if (staleFiles(step, [jsonpath])) {
var parser = new basic_compiler.BASICParser();
var code = getWorkFileAsString(step.path);
try {
var ast = parser.parseFile(code, step.path);
} catch (e) {
console.log(e);
if (parser.errors.length == 0) throw e;
}
if (parser.errors.length) {
return { errors: parser.errors };
}
// put AST into JSON (sans source locations) to see if it has changed
var json = JSON.stringify(ast, (key, value) => { return (key == '$loc' ? undefined : value) });
putWorkFile(jsonpath, json);
if (anyTargetChanged(step, [jsonpath])) return {
output: ast,
listings: parser.getListings(),
};
}
}
export function compileWiz(step: BuildStep): WorkerResult {
loadNative("wiz");
var params = step.params;
gatherFiles(step, { mainFilePath: "main.wiz" });
var destpath = step.prefix + (params.wiz_rom_ext || ".bin");
var errors: WorkerError[] = [];
if (staleFiles(step, [destpath])) {
var wiz: EmscriptenModule = emglobal.wiz({
instantiateWasm: moduleInstFn('wiz'),
noInitialRun: true,
print: print_fn,
//test.wiz:2: error: expected statement, but got identifier `test`
printErr: makeErrorMatcher(errors, /(.+?):(\d+):\s*(.+)/, 2, 3, step.path, 1),
});
var FS = wiz.FS;
setupFS(FS, 'wiz');
populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_compile_files);
const FWDIR = '/share/common';
var args = [
'-o', destpath,
'-I', FWDIR + '/' + (params.wiz_inc_dir || getRootBasePlatform(step.platform)),
'-s', 'wla',
'--color=none',
step.path];
args.push('--system', params.wiz_sys_type || params.arch);
execMain(step, wiz, args);
if (errors.length)
return { errors: errors };
var binout = FS.readFile(destpath, { encoding: 'binary' });
putWorkFile(destpath, binout);
var dbgout = FS.readFile(step.prefix + '.sym', { encoding: 'utf8' });
var symbolmap = {};
for (var s of dbgout.split("\n")) {
var toks = s.split(/ /);
// 00:4008 header.basic_start
if (toks && toks.length >= 2) {
var tokrange = toks[0].split(':');
var start = parseInt(tokrange[1], 16);
var sym = toks[1];
symbolmap[sym] = start;
}
}
return {
output: binout, //.slice(0),
errors: errors,
symbolmap: symbolmap,
};
}
}