2018-07-06 00:13:07 +00:00
|
|
|
|
2021-08-15 15:10:01 +00:00
|
|
|
import { FileData, Dependency, SourceLine, SourceFile, CodeListing, CodeListingMap, WorkerError, Segment, WorkerResult, WorkerOutputResult, isUnchanged, isOutputResult, WorkerMessage, WorkerItemUpdate } from "../common/workertypes";
|
2021-04-06 16:37:41 +00:00
|
|
|
import { getFilenamePrefix, getFolderForPath, isProbablyBinary, getBasePlatform, getWithBinary } from "../common/util";
|
2019-10-26 01:55:50 +00:00
|
|
|
import { Platform } from "../common/baseplatform";
|
2021-08-04 17:00:10 +00:00
|
|
|
import localforage from "localforage";
|
2018-07-06 00:13:07 +00:00
|
|
|
|
2021-04-06 16:37:41 +00:00
|
|
|
export interface ProjectFilesystem {
|
|
|
|
getFileData(path: string) : Promise<FileData>;
|
|
|
|
setFileData(path: string, data: FileData) : Promise<void>;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class WebPresetsFileSystem implements ProjectFilesystem {
|
|
|
|
preset_id : string;
|
|
|
|
constructor(platform_id: string) {
|
|
|
|
this.preset_id = getBasePlatform(platform_id); // remove .suffix from preset name
|
|
|
|
}
|
|
|
|
async getRemoteFile(path: string): Promise<FileData> {
|
|
|
|
return new Promise( (yes,no)=> {
|
|
|
|
return getWithBinary(path, yes, isProbablyBinary(path) ? 'arraybuffer' : 'text');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
async getFileData(path: string) : Promise<FileData> {
|
2021-04-07 15:22:49 +00:00
|
|
|
// found on remote fetch?
|
2021-04-06 16:37:41 +00:00
|
|
|
var webpath = "presets/" + this.preset_id + "/" + path;
|
|
|
|
var data = await this.getRemoteFile(webpath);
|
|
|
|
if (data) console.log("read",webpath,data.length,'bytes');
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
async setFileData(path: string, data: FileData) : Promise<void> {
|
|
|
|
// not implemented
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class NullFilesystem implements ProjectFilesystem {
|
|
|
|
gets = [];
|
|
|
|
sets = [];
|
|
|
|
getFileData(path: string): Promise<FileData> {
|
|
|
|
this.gets.push(path);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
setFileData(path: string, data: FileData): Promise<void> {
|
|
|
|
this.sets.push(path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-04-07 15:22:49 +00:00
|
|
|
export class OverlayFilesystem implements ProjectFilesystem {
|
2021-04-06 16:37:41 +00:00
|
|
|
basefs: ProjectFilesystem;
|
2021-04-07 15:22:49 +00:00
|
|
|
overlayfs: ProjectFilesystem;
|
|
|
|
constructor(basefs: ProjectFilesystem, overlayfs: ProjectFilesystem) {
|
2021-04-06 16:37:41 +00:00
|
|
|
this.basefs = basefs;
|
2021-04-07 15:22:49 +00:00
|
|
|
this.overlayfs = overlayfs;
|
2021-04-06 16:37:41 +00:00
|
|
|
}
|
|
|
|
async getFileData(path: string): Promise<FileData> {
|
2021-04-07 15:22:49 +00:00
|
|
|
var data = await this.overlayfs.getFileData(path);
|
2021-04-06 16:37:41 +00:00
|
|
|
if (data == null) {
|
2021-04-07 15:22:49 +00:00
|
|
|
return this.basefs.getFileData(path);
|
|
|
|
} else {
|
|
|
|
return data;
|
2021-04-06 16:37:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
async setFileData(path: string, data: FileData): Promise<void> {
|
2021-04-07 15:22:49 +00:00
|
|
|
await this.overlayfs.setFileData(path, data);
|
|
|
|
return this.basefs.setFileData(path, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class LocalForageFilesystem {
|
|
|
|
store: any;
|
|
|
|
constructor(store: any) {
|
|
|
|
this.store = store;
|
|
|
|
}
|
|
|
|
async getFileData(path: string): Promise<FileData> {
|
|
|
|
return this.store.getItem(path);
|
|
|
|
}
|
|
|
|
async setFileData(path: string, data: FileData): Promise<void> {
|
|
|
|
return this.store.setItem(path, data);
|
2021-04-06 16:37:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-26 13:43:49 +00:00
|
|
|
type BuildResultCallback = (result:WorkerResult) => void;
|
2018-07-06 00:13:07 +00:00
|
|
|
type BuildStatusCallback = (busy:boolean) => void;
|
|
|
|
type IterateFilesCallback = (path:string, data:FileData) => void;
|
|
|
|
|
2020-08-02 04:06:18 +00:00
|
|
|
function isEmptyString(text : FileData) {
|
|
|
|
return typeof text == 'string' && text.trim && text.trim().length == 0;
|
|
|
|
}
|
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
export class CodeProject {
|
|
|
|
filedata : {[path:string]:FileData} = {};
|
|
|
|
listings : CodeListingMap;
|
2019-02-21 21:47:25 +00:00
|
|
|
segments : Segment[];
|
2019-12-27 19:19:11 +00:00
|
|
|
mainPath : string;
|
2018-07-06 00:13:07 +00:00
|
|
|
pendingWorkerMessages = 0;
|
|
|
|
tools_preloaded = {};
|
2018-07-08 04:58:11 +00:00
|
|
|
worker : Worker;
|
2018-07-06 00:13:07 +00:00
|
|
|
platform_id : string;
|
2019-05-06 01:49:08 +00:00
|
|
|
platform : Platform;
|
2018-09-11 00:44:53 +00:00
|
|
|
isCompiling : boolean = false;
|
2019-12-27 22:31:24 +00:00
|
|
|
filename2path = {}; // map stripped paths to full paths
|
2021-04-06 16:37:41 +00:00
|
|
|
filesystem : ProjectFilesystem;
|
2021-08-15 15:10:01 +00:00
|
|
|
dataItems : WorkerItemUpdate[];
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2020-08-27 01:42:18 +00:00
|
|
|
callbackBuildResult : BuildResultCallback;
|
|
|
|
callbackBuildStatus : BuildStatusCallback;
|
|
|
|
|
2021-04-06 16:37:41 +00:00
|
|
|
constructor(worker, platform_id:string, platform, filesystem: ProjectFilesystem) {
|
2018-07-06 00:13:07 +00:00
|
|
|
this.worker = worker;
|
|
|
|
this.platform_id = platform_id;
|
|
|
|
this.platform = platform;
|
2021-04-06 16:37:41 +00:00
|
|
|
this.filesystem = filesystem;
|
2018-07-06 00:13:07 +00:00
|
|
|
|
|
|
|
worker.onmessage = (e) => {
|
2018-12-01 11:48:33 +00:00
|
|
|
this.receiveWorkerMessage(e.data);
|
2018-07-06 00:13:07 +00:00
|
|
|
};
|
|
|
|
}
|
2019-03-02 23:15:03 +00:00
|
|
|
|
2018-12-01 11:48:33 +00:00
|
|
|
receiveWorkerMessage(data : WorkerResult) {
|
|
|
|
var notfinal = this.pendingWorkerMessages > 1;
|
|
|
|
if (notfinal) {
|
|
|
|
this.sendBuild();
|
|
|
|
this.pendingWorkerMessages = 1;
|
|
|
|
} else {
|
|
|
|
if (this.callbackBuildStatus) this.callbackBuildStatus(false);
|
|
|
|
if (!this.isCompiling) { console.log(this.pendingWorkerMessages); console.trace(); } // debug compile problems
|
|
|
|
this.isCompiling = false;
|
|
|
|
this.pendingWorkerMessages = 0;
|
|
|
|
}
|
2021-08-08 18:40:19 +00:00
|
|
|
if (data && isOutputResult(data)) {
|
2018-12-01 11:48:33 +00:00
|
|
|
this.processBuildResult(data);
|
|
|
|
}
|
2020-10-16 11:14:40 +00:00
|
|
|
this.callbackBuildResult(data);
|
2018-12-01 11:48:33 +00:00
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
preloadWorker(path:string) {
|
|
|
|
var tool = this.platform.getToolForFilename(path);
|
|
|
|
if (tool && !this.tools_preloaded[tool]) {
|
|
|
|
this.worker.postMessage({preload:tool, platform:this.platform_id});
|
|
|
|
this.tools_preloaded[tool] = true;
|
|
|
|
}
|
|
|
|
}
|
2019-03-02 23:15:03 +00:00
|
|
|
|
2018-11-27 15:14:24 +00:00
|
|
|
pushAllFiles(files:string[], fn:string) {
|
|
|
|
// look for local and preset files
|
|
|
|
files.push(fn);
|
|
|
|
// look for files in current (main file) folder
|
2020-08-09 20:52:26 +00:00
|
|
|
var dir = getFolderForPath(this.mainPath);
|
2018-11-27 20:14:22 +00:00
|
|
|
if (dir.length > 0 && dir != 'local') // TODO
|
2018-11-27 15:14:24 +00:00
|
|
|
files.push(dir + '/' + fn);
|
|
|
|
}
|
2019-03-02 23:15:03 +00:00
|
|
|
|
2022-02-03 02:06:44 +00:00
|
|
|
// TODO: use tool id to parse files, not platform
|
2018-08-03 18:06:08 +00:00
|
|
|
parseIncludeDependencies(text:string):string[] {
|
2019-04-24 17:46:19 +00:00
|
|
|
let files = [];
|
|
|
|
let m;
|
2021-08-15 15:10:01 +00:00
|
|
|
if (this.platform_id.startsWith('script')) { // TODO
|
|
|
|
let re1 = /\b\w+[.]read\(["'](.+?)["']/gmi;
|
|
|
|
while (m = re1.exec(text)) {
|
|
|
|
if (m[1] && m[1].indexOf(':/') < 0) // TODO: ignore URLs
|
|
|
|
this.pushAllFiles(files, m[1]);
|
|
|
|
}
|
|
|
|
} else if (this.platform_id.startsWith('verilog')) {
|
2018-12-03 15:51:47 +00:00
|
|
|
// include verilog includes
|
2019-04-24 17:46:19 +00:00
|
|
|
let re1 = /^\s*(`include|[.]include)\s+"(.+?)"/gmi;
|
2018-11-28 16:10:24 +00:00
|
|
|
while (m = re1.exec(text)) {
|
2018-11-27 15:14:24 +00:00
|
|
|
this.pushAllFiles(files, m[2]);
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2020-12-16 16:48:33 +00:00
|
|
|
// for Silice
|
|
|
|
let re1a = /^\s*\$(include|\$dofile|\$write_image_in_table)\('(.+?)'/gmi;
|
|
|
|
while (m = re1a.exec(text)) {
|
|
|
|
this.pushAllFiles(files, m[2]);
|
|
|
|
}
|
2018-11-28 16:10:24 +00:00
|
|
|
// include .arch (json) statements
|
2019-04-24 17:46:19 +00:00
|
|
|
let re2 = /^\s*([.]arch)\s+(\w+)/gmi;
|
2018-11-28 16:10:24 +00:00
|
|
|
while (m = re2.exec(text)) {
|
|
|
|
this.pushAllFiles(files, m[2]+".json");
|
|
|
|
}
|
2018-12-03 15:51:47 +00:00
|
|
|
// include $readmem[bh] (TODO)
|
2019-05-02 03:33:49 +00:00
|
|
|
let re3 = /\$readmem[bh]\("(.+?)"/gmi;
|
2018-12-03 15:51:47 +00:00
|
|
|
while (m = re3.exec(text)) {
|
2019-05-02 03:33:49 +00:00
|
|
|
this.pushAllFiles(files, m[1]);
|
2018-12-03 15:51:47 +00:00
|
|
|
}
|
2018-07-06 00:13:07 +00:00
|
|
|
} else {
|
2020-07-10 18:25:34 +00:00
|
|
|
// for .asm -- [.%]include "file"
|
2018-08-12 23:59:08 +00:00
|
|
|
// for .c -- #include "file"
|
2020-07-10 18:25:34 +00:00
|
|
|
let re2 = /^\s*[.#%]?(include|incbin)\s+"(.+?)"/gmi;
|
2018-08-03 18:06:08 +00:00
|
|
|
while (m = re2.exec(text)) {
|
2018-11-27 15:14:24 +00:00
|
|
|
this.pushAllFiles(files, m[2]);
|
2018-08-03 18:06:08 +00:00
|
|
|
}
|
2019-05-22 01:39:37 +00:00
|
|
|
// for .c -- //#resource "file" (or ;resource or #resource)
|
2020-12-16 16:48:33 +00:00
|
|
|
let re3 = /^\s*([;']|[/][/])#resource\s+"(.+?)"/gm;
|
2019-04-24 17:46:19 +00:00
|
|
|
while (m = re3.exec(text)) {
|
|
|
|
this.pushAllFiles(files, m[2]);
|
|
|
|
}
|
2020-06-30 17:10:15 +00:00
|
|
|
// for XASM only (USE include.ext)
|
2020-07-25 23:33:55 +00:00
|
|
|
// for merlin32 (ASM include.ext)
|
|
|
|
let re4 = /^\s+(USE|ASM)\s+(\S+[.]\S+)/gm;
|
2020-06-30 17:10:15 +00:00
|
|
|
while (m = re4.exec(text)) {
|
|
|
|
this.pushAllFiles(files, m[2]);
|
|
|
|
}
|
2021-03-04 14:20:00 +00:00
|
|
|
// for wiz
|
2022-02-03 02:06:44 +00:00
|
|
|
let re5 = /^\s*(import|embed)\s*"(.+?)";/gmi;
|
2021-03-04 14:20:00 +00:00
|
|
|
while (m = re5.exec(text)) {
|
2021-06-20 21:38:54 +00:00
|
|
|
if (m[1] == 'import')
|
|
|
|
this.pushAllFiles(files, m[2] + ".wiz");
|
|
|
|
else
|
|
|
|
this.pushAllFiles(files, m[2]);
|
2021-03-04 14:20:00 +00:00
|
|
|
}
|
2022-02-03 02:06:44 +00:00
|
|
|
// for ecs
|
|
|
|
let re6 = /^\s*(import)\s*"(.+?)"/gmi;
|
|
|
|
while (m = re6.exec(text)) {
|
|
|
|
this.pushAllFiles(files, m[2]);
|
|
|
|
}
|
2018-08-03 18:06:08 +00:00
|
|
|
}
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
|
|
|
parseLinkDependencies(text:string):string[] {
|
2019-04-24 17:46:19 +00:00
|
|
|
let files = [];
|
|
|
|
let m;
|
2018-11-18 17:30:41 +00:00
|
|
|
if (this.platform_id.startsWith('verilog')) {
|
2018-08-03 18:06:08 +00:00
|
|
|
//
|
|
|
|
} else {
|
|
|
|
// for .c -- //#link "file" (or ;link or #link)
|
2019-05-22 01:39:37 +00:00
|
|
|
let re = /^\s*([;]|[/][/])#link\s+"(.+?)"/gm;
|
2018-07-06 00:13:07 +00:00
|
|
|
while (m = re.exec(text)) {
|
2018-11-27 15:14:24 +00:00
|
|
|
this.pushAllFiles(files, m[2]);
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return files;
|
|
|
|
}
|
2019-05-31 19:05:33 +00:00
|
|
|
|
2019-05-23 12:32:53 +00:00
|
|
|
loadFileDependencies(text:string) : Promise<Dependency[]> {
|
2019-04-24 17:46:19 +00:00
|
|
|
let includes = this.parseIncludeDependencies(text);
|
|
|
|
let linkfiles = this.parseLinkDependencies(text);
|
|
|
|
let allfiles = includes.concat(linkfiles);
|
2019-05-23 12:32:53 +00:00
|
|
|
return this.loadFiles(allfiles).then((result) => {
|
2018-08-14 20:28:29 +00:00
|
|
|
// set 'link' property on files that are link dependencies (must match filename)
|
2019-04-24 17:46:19 +00:00
|
|
|
if (result) {
|
|
|
|
for (let dep of result) {
|
2018-11-27 15:14:24 +00:00
|
|
|
dep.link = linkfiles.indexOf(dep.path) >= 0;
|
2019-04-24 17:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-23 12:32:53 +00:00
|
|
|
return result;
|
2018-08-03 18:06:08 +00:00
|
|
|
});
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
okToSend():boolean {
|
2021-08-15 15:10:01 +00:00
|
|
|
return this.pendingWorkerMessages++ == 0 && this.mainPath != null;
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
updateFileInStore(path:string, text:FileData) {
|
2021-04-06 16:37:41 +00:00
|
|
|
this.filesystem.setFileData(path, text);
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
// TODO: test duplicate files, local paths mixed with presets
|
2021-08-15 15:10:01 +00:00
|
|
|
buildWorkerMessage(depends:Dependency[]) : WorkerMessage {
|
2020-08-09 20:52:26 +00:00
|
|
|
this.preloadWorker(this.mainPath);
|
2021-08-15 15:10:01 +00:00
|
|
|
var msg : WorkerMessage = {updates:[], buildsteps:[]};
|
2018-07-06 00:13:07 +00:00
|
|
|
// TODO: add preproc directive for __MAINFILE__
|
2020-08-09 20:52:26 +00:00
|
|
|
var mainfilename = this.stripLocalPath(this.mainPath);
|
|
|
|
var maintext = this.getFile(this.mainPath);
|
2018-08-12 23:59:08 +00:00
|
|
|
var depfiles = [];
|
2018-07-06 00:13:07 +00:00
|
|
|
msg.updates.push({path:mainfilename, data:maintext});
|
2020-08-09 20:52:26 +00:00
|
|
|
this.filename2path[mainfilename] = this.mainPath;
|
2018-08-03 18:06:08 +00:00
|
|
|
for (var dep of depends) {
|
|
|
|
if (!dep.link) {
|
|
|
|
msg.updates.push({path:dep.filename, data:dep.data});
|
2018-08-12 23:59:08 +00:00
|
|
|
depfiles.push(dep.filename);
|
2018-08-03 18:06:08 +00:00
|
|
|
}
|
2019-12-27 22:31:24 +00:00
|
|
|
this.filename2path[dep.filename] = dep.path;
|
2018-08-03 18:06:08 +00:00
|
|
|
}
|
2020-08-09 20:52:26 +00:00
|
|
|
msg.buildsteps.push({
|
|
|
|
path:mainfilename,
|
|
|
|
files:[mainfilename].concat(depfiles),
|
|
|
|
platform:this.platform_id,
|
|
|
|
tool:this.platform.getToolForFilename(this.mainPath),
|
|
|
|
mainfile:true});
|
2018-08-03 18:06:08 +00:00
|
|
|
for (var dep of depends) {
|
|
|
|
if (dep.data && dep.link) {
|
2018-07-06 00:13:07 +00:00
|
|
|
this.preloadWorker(dep.filename);
|
|
|
|
msg.updates.push({path:dep.filename, data:dep.data});
|
2020-08-09 20:52:26 +00:00
|
|
|
msg.buildsteps.push({
|
|
|
|
path:dep.filename,
|
|
|
|
files:[dep.filename].concat(depfiles),
|
|
|
|
platform:this.platform_id,
|
|
|
|
tool:this.platform.getToolForFilename(dep.path)});
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-15 15:10:01 +00:00
|
|
|
if (this.dataItems) msg.setitems = this.dataItems;
|
2018-07-06 00:13:07 +00:00
|
|
|
return msg;
|
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
|
|
|
// TODO: get local file as well as presets?
|
2021-04-06 16:37:41 +00:00
|
|
|
async loadFiles(paths:string[]) : Promise<Dependency[]> {
|
2018-07-06 23:12:58 +00:00
|
|
|
var result : Dependency[] = [];
|
2021-04-06 16:37:41 +00:00
|
|
|
var addResult = (path:string, data:FileData) => {
|
2018-07-06 23:12:58 +00:00
|
|
|
result.push({
|
|
|
|
path:path,
|
2019-04-26 19:38:34 +00:00
|
|
|
filename:this.stripLocalPath(path),
|
2018-08-03 18:06:08 +00:00
|
|
|
link:true,
|
2018-07-06 23:12:58 +00:00
|
|
|
data:data
|
|
|
|
});
|
|
|
|
}
|
2021-04-06 16:37:41 +00:00
|
|
|
for (var path of paths) {
|
|
|
|
// look in cache
|
|
|
|
if (path in this.filedata) { // found in cache?
|
|
|
|
var data = this.filedata[path];
|
|
|
|
if (data) {
|
|
|
|
addResult(path, data);
|
|
|
|
}
|
2018-07-06 00:13:07 +00:00
|
|
|
} else {
|
2021-04-06 16:37:41 +00:00
|
|
|
var data = await this.filesystem.getFileData(path);
|
|
|
|
if (data) {
|
|
|
|
this.filedata[path] = data; // do not update store, just cache
|
|
|
|
addResult(path, data);
|
2018-07-24 15:38:56 +00:00
|
|
|
} else {
|
2021-04-06 16:37:41 +00:00
|
|
|
this.filedata[path] = null; // mark entry as invalid
|
2018-07-24 15:38:56 +00:00
|
|
|
}
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-06 16:37:41 +00:00
|
|
|
return result;
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
getFile(path:string):FileData {
|
|
|
|
return this.filedata[path];
|
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-08-03 18:06:08 +00:00
|
|
|
// TODO: purge files not included in latest build?
|
2018-07-06 00:13:07 +00:00
|
|
|
iterateFiles(callback:IterateFilesCallback) {
|
|
|
|
for (var path in this.filedata) {
|
|
|
|
callback(path, this.getFile(path));
|
|
|
|
}
|
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
sendBuild() {
|
2020-08-09 20:52:26 +00:00
|
|
|
if (!this.mainPath) throw Error("need to call setMainFile first");
|
|
|
|
var maindata = this.getFile(this.mainPath);
|
2018-12-01 11:48:33 +00:00
|
|
|
// if binary blob, just return it as ROM
|
|
|
|
if (maindata instanceof Uint8Array) {
|
|
|
|
this.isCompiling = true;
|
|
|
|
this.receiveWorkerMessage({
|
|
|
|
output:maindata,
|
|
|
|
errors:[],
|
|
|
|
listings:null,
|
|
|
|
symbolmap:null,
|
|
|
|
params:{}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// otherwise, make it a string
|
2018-07-06 00:13:07 +00:00
|
|
|
var text = typeof maindata === "string" ? maindata : '';
|
2018-08-12 23:59:08 +00:00
|
|
|
// TODO: load dependencies of non-main files
|
2019-05-23 12:32:53 +00:00
|
|
|
return this.loadFileDependencies(text).then( (depends) => {
|
2018-07-06 06:42:01 +00:00
|
|
|
if (!depends) depends = [];
|
2018-12-15 18:14:40 +00:00
|
|
|
var workermsg = this.buildWorkerMessage(depends);
|
|
|
|
this.worker.postMessage(workermsg);
|
2018-09-11 00:44:53 +00:00
|
|
|
this.isCompiling = true;
|
2018-07-06 00:13:07 +00:00
|
|
|
});
|
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
updateFile(path:string, text:FileData) {
|
2020-08-29 22:30:39 +00:00
|
|
|
if (this.filedata[path] == text) return; // unchanged, don't update
|
2018-07-06 00:13:07 +00:00
|
|
|
this.updateFileInStore(path, text); // TODO: isBinary
|
|
|
|
this.filedata[path] = text;
|
2021-08-15 15:10:01 +00:00
|
|
|
if (this.okToSend()) {
|
2018-07-06 00:13:07 +00:00
|
|
|
if (this.callbackBuildStatus) this.callbackBuildStatus(true);
|
|
|
|
this.sendBuild();
|
|
|
|
}
|
|
|
|
};
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-08-04 14:21:50 +00:00
|
|
|
setMainFile(path:string) {
|
2020-08-09 20:52:26 +00:00
|
|
|
this.mainPath = path;
|
2018-08-04 14:21:50 +00:00
|
|
|
if (this.callbackBuildStatus) this.callbackBuildStatus(true);
|
|
|
|
this.sendBuild();
|
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2021-08-08 18:40:19 +00:00
|
|
|
processBuildResult(data: WorkerOutputResult<any>) {
|
2018-07-06 00:13:07 +00:00
|
|
|
// TODO: link listings with source files
|
2018-09-05 02:28:12 +00:00
|
|
|
if (data.listings) {
|
|
|
|
this.listings = data.listings;
|
2018-07-06 00:13:07 +00:00
|
|
|
for (var lstname in this.listings) {
|
|
|
|
var lst = this.listings[lstname];
|
2019-02-22 16:43:07 +00:00
|
|
|
if (lst.lines)
|
2019-02-21 00:38:30 +00:00
|
|
|
lst.sourcefile = new SourceFile(lst.lines, lst.text);
|
2019-02-22 16:43:07 +00:00
|
|
|
if (lst.asmlines)
|
2018-07-06 00:13:07 +00:00
|
|
|
lst.assemblyfile = new SourceFile(lst.asmlines, lst.text);
|
|
|
|
}
|
|
|
|
}
|
2019-02-21 21:47:25 +00:00
|
|
|
// save and sort segment list
|
2019-08-27 16:12:56 +00:00
|
|
|
var segs = (this.platform.getMemoryMap && this.platform.getMemoryMap()["main"]) || [];
|
2020-07-09 02:57:55 +00:00
|
|
|
if (data.segments) { segs = segs.concat(data.segments || []); }
|
2019-08-27 16:12:56 +00:00
|
|
|
segs.sort((a,b) => {return a.start-b.start});
|
|
|
|
this.segments = segs;
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2018-11-21 12:21:07 +00:00
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
getListings() : CodeListingMap {
|
|
|
|
return this.listings;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns first listing in format [prefix].lst (TODO: could be better)
|
2021-04-05 17:11:38 +00:00
|
|
|
getListingForFile(path: string) : CodeListing {
|
2019-12-27 22:31:24 +00:00
|
|
|
// ignore include files (TODO)
|
2021-04-08 15:33:48 +00:00
|
|
|
//if (path.toLowerCase().endsWith('.h') || path.toLowerCase().endsWith('.inc'))
|
|
|
|
//return;
|
2019-04-26 19:38:34 +00:00
|
|
|
var fnprefix = getFilenamePrefix(this.stripLocalPath(path));
|
2018-07-06 00:13:07 +00:00
|
|
|
var listings = this.getListings();
|
2021-04-05 17:11:38 +00:00
|
|
|
var onlyfile = null;
|
2018-07-06 00:13:07 +00:00
|
|
|
for (var lstfn in listings) {
|
2021-04-05 17:11:38 +00:00
|
|
|
onlyfile = lstfn;
|
2018-07-06 00:13:07 +00:00
|
|
|
if (getFilenamePrefix(lstfn) == fnprefix) {
|
|
|
|
return listings[lstfn];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-26 19:38:34 +00:00
|
|
|
|
|
|
|
stripLocalPath(path : string) : string {
|
2019-05-07 19:37:37 +00:00
|
|
|
if (this.mainPath) {
|
|
|
|
var folder = getFolderForPath(this.mainPath);
|
|
|
|
if (folder != '' && path.startsWith(folder)) {
|
|
|
|
path = path.substring(folder.length+1);
|
|
|
|
}
|
2019-04-26 19:38:34 +00:00
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
2019-12-27 19:19:11 +00:00
|
|
|
|
2021-08-15 15:10:01 +00:00
|
|
|
updateDataItems(items: WorkerItemUpdate[]) {
|
|
|
|
this.dataItems = items;
|
|
|
|
if (this.okToSend()) { // TODO? mainpath == null?
|
|
|
|
this.sendBuild(); // TODO: don't need entire build?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 00:13:07 +00:00
|
|
|
}
|
2021-08-04 17:00:10 +00:00
|
|
|
|
|
|
|
export function createNewPersistentStore(storeid:string) : LocalForage {
|
|
|
|
var store = localforage.createInstance({
|
|
|
|
name: "__" + storeid,
|
|
|
|
version: 2.0
|
|
|
|
});
|
|
|
|
return store;
|
|
|
|
}
|
|
|
|
|